不用比较返回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;才是正 确的比较。
[1] [2] 下一页
另外一个quick check是if(this==obj) return true;
是否equals方法一定比较的两个对象就一定是要同一类型?上面我用了"通常",这也是绝大多数程序 员的愿望,但是有些特殊的情况,我们可以进行不同类型的比较,这并不违反规范。但这种特殊情况 是非常罕见的,一个不恰当的例子是,Integer类的equals可以和Sort做比较,比较它们的value是不 是同一数学值。(事实上JDK的API中并没有这样做,所以我才说是不恰当的例子)
在完成quick check以后,我们就要真正实现你认为的“相等”。对于如果实现对象相等,没有太高 的要求,比如你自己实现的“人”类,你可以认为只要name相同即认为它们是相等的,其它的sex, ago都可以不考虑。这是不完全实现,但是如果是完全实现,即要求所有的属性都是相同的,那么如 何实现equals方法?
class Human{ private String name; private int ago; private String sex; .................... public boolean equals(Object obj){ quick check....... Human other = (Human)ojb; return this.name.equals(other.name) && this.ago == ohter.ago && this.sex.equals(other.sex); } }
这是一个完全实现,但是,有时equals实现是在父类中实现,而要求被子类继承后equals能正确的工 作,这时你并不事实知道子类到底扩展了哪些属性,所以用上面的方法无法使equals得到完全实现。 一个好的方法是利用反射来对equals进行完全实现:
public boolean equals(Object obj){ quick check....... Class c = this.getClass(); Filed[] fds = c.getDeclaredFields(); for(Filed f:fds){ if(!f.get(this).equals(f.get(obj))) return false; } return true; } 为了说明的方便,上明的实现省略了异常,这样的实现放在父类中,可以保证你的子类的equals可以按 你的愿望正确地工作。
关于equals方法的最后一点是:如果你要是自己重写(正确说应该是履盖)了equals方法,那同时就一 定要重写hashCode().为是规范,否则............. 我们还是看一下这个例子:
public final class PhoneNumber { private final int areaCode; private final int exchange; private final int extension;
public PhoneNumber(int areaCode, int exchange, int extension) { rangeCheck(areaCode, 999, "area code"); rangeCheck(exchange, 99999999, "ex 上一页 [1] [2] [3] 下一页
|