扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
在本页阅读全文(共2页)
下面的内容只是API的规范,没有什么太高深的意义,但我之所以最先把它列在这儿,是因为这些规范在事实中并不是真正能保证得到实现.
1.对于任何引用类型, o.equals(o) == true成立.
2.如果 o.equals(o1) == true 成立,那么o1.equals(o)==true也一定要成立.
3.如果 o.equals(o1) == true 成立且 o.equals(o2) == true 成立,那么
o1.equals(o2) == true 也成立.
4.如果第一次调用o.equals(o1) == true成立,在o和o1没有改变的情况下以后的任何次调用都成立.
5.o.equals(null) == true 任何时间都不成立.
以上几条规则并不是最完整的表述,详细的请参见API文档.对于Object类,它提供了一个最最严密的实现,那就是只有是同一对象时,equals方法才返回true,也就是人们常说的引用比较而不是值比较.这个实现严密得已经没有什么实际的意义, 所以在具体子类(相对于Object来说)中,如果我们要进行对象的值比较,就必须实现自己的equals方法.先来看一下以下这段
以下是引用片段: public boolean equals(Object obj) { if (obj == null) return false; if (!(obj instanceof FieldPosition)) return false; FieldPosition other = (FieldPosition) obj; if (attribute == null) { if (other.attribute != null) { return false; } } else if (!attribute.equals(other.attribute)) { return false; } return (beginIndex == other.beginIndex && endIndex == other.endIndex && field == other.field); } |
这是JDK中
以下是引用片段: package debug ;import java.text.*; public class Test { public static void main(String[] args) { FieldPosition fp = new FieldPosition(10); FieldPosition fp1 = new MyTest(10); System.out.println(fp.equals(fp1)); System.out.println(fp1.equals(fp)); } } class MyTest extends FieldPosition{ int x = 10; public MyTest(int x){ super(x); this.x = x; } public boolean equals(Object o){ if(o==null) return false; if(!(o instanceof MyTest )) return false; return ((MyTest)o).x == this.x; } } |
运行一下看看会打印出什么:
以下是引用片段: System.out.println(fp.equals(fp1));打印true System.out.println(fp1.equals(fp));打印flase |
两个对象,出现了不对称的equals算法.问题出在哪里(脑筋急转弯:当然出在JDK实现的BUG)?我相信有太多的程序员(除了那些根本不知道实现equals方法的程序员外)在实现equals方法时都用过instanceof运行符来进行短路优化的,实事求是地说很长一段时间我也这么用过。
太多的教程,文档都给了我们这样的误导。而有些稍有了解的程序员可能知道这样的优化可能有些不对但找不出问题的关键。另外一种极端是知道这个技术缺陷的骨灰级
但事实上,"子类是父类的一个实例",所以如果子类 o instanceof 父类,始终返回true,这时肯定不会发生短路优化,下面的比较有可能出现多种情况,一种是不能造型成父类而抛出异常,另一种是父类的private 成员没有被子类继承而不能进行比较,还有就是形成上面这种不对称比较。可能会出现太多的情况。
那么,是不是就不能用 instanceof运算符来进行优化?答案是否定的,JDK中仍然有很多实现是正确的,如果一个class是final的,明知它不可能有子类,为什么不用 instanceof来优化呢?为了维护SUN的
以下是引用片段: if (this == obj) // quick check return true; if (!(obj instanceof XXXXClass)) // (1) same object? return false; |
可能是有些疑问,但不知道如何做(不知道为什么没有打电话给我......)那么对于非final类,如何进行类型的quick check呢?
以下是引用片段: if(obj.getClass() != XXXClass.class) return false; |
用被比较对象的class对象和当前对象的class比较,看起来是没有问题,但是,如果这个类的子类没有重新实现equals方法,那么子类在比较的时候,obj.getClass() 肯定不等于XXXCalss.class, 也就是子类的equals将无效,所以
以下是引用片段: if(obj.getClass() != this.getClass()) return false; |
才是正确的比较。另外一个quick check是if(this==obj) return true;
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者