上一篇 | 下一篇

BEA dev2dev WebLogic Web Application Development精华

发布: 2008-7-01 21:20 | 作者: admin | 来源: | 查看: 4次

运行一下看看会打印出什么:

System.out.println(fp.equals(fp1));打印true

System.out.println(fp1.equals(fp));打印flase

两个对象,出现了不对称的equals算法.问题出在哪里(脑筋急转弯:当然出在JDK实现的BUG)?

我相信有太多的程序员(除了那些根本不知道实现equals方法的程序员外)在实现equals方法

时都用过instanceof运行符来进行短路优化的,实事求是地说很长一段时间我也这么用过。

太多的教程,文档都给了我们这样的误导。而有些稍有了解的程序员可能知道这样的优化可能

有些不对但找不出问题的关键。另外一种极端是知道这个技术缺陷的骨灰级专家就提议不要这

样应用。

我们知道,"通常"要对两个对象进行比较,那么它们"应该"是同一类型。所以首先利用instanceof

运行符进行短路优化,如果被比较的对象不和当前对象是同一类型则不用比较返回false,但事实

上,"子类是父类的一个实例",所以如果子类 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;才是正

确的比较。

是否equals方法一定比较的两个对象就一定是要同一类型?上面我用了"通常",这也是绝大多数程序

员的愿望,但是有些特殊的情况,我们可以进行不同类型的比较,这并不违反规范。但这种特殊情况

是非常罕见的,一个不恰当的例子是,Integer类的equals可以和Sort做比较,比较它们的value是不

是同一数学值。(事实上JDK的API中并没有这样做,所以我才说是不恰当的例子)

在完成quick check以后,我们就要真正实现你认为的“相等”。对于如果实现对象相等,没有太高

的要求,比如你自己实现的“人”类,你可以认为只要name相同即认为它们是相等的,其它的sex,

ago都可以不考虑。这是不完全实现,但是如果是完全实现,即要求所有的属性都是相同的,那么如

[8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21]

字号: | 推荐给好友

评分:0

我来说两句