本节我们继续讨论覆写equals的问题。这次我们编写一个员工Employee类继承Person类,这很正常,员工也是人嘛,而且在JEE中JavaBean有继承关系也很常见,代码如下:
1 public class Client { 2 public static void main(String[] args) { 3 Employee e1 = new Employee("张三",100); 4 Employee e2 = new Employee("张三",1001); 5 Person p1 = new Person("张三"); 6 System.out.println(p1.equals(e1)); 7 System.out.println(p1.equals(e2)); 8 System.out.println(e1.equals(e2)); 9 } 10 } 11 12 class Person{ 13 private String name; 14 15 public Person(String _name){ 16 name = _name; 17 } 18 19 @Override 20 public boolean equals(Object obj) { 21 if(obj instanceof Person){ 22 Person p = (Person) obj; 23 return name.equalsIgnoreCase(p.getName().trim()); 24 } 25 return false; 26 } 27 28 public String getName() { 29 return name; 30 } 31 32 public void setName(String name) { 33 this.name = name; 34 } 35 } 36 37 class Employee extends Person{ 38 private int id; 39 /*id的getter/setter方法省略*/ 40 public Employee(String _name,int _id) { 41 super(_name); 42 id = _id; 43 } 44 45 public int getId() { 46 return id; 47 } 48 49 public void setId(int id) { 50 this.id = id; 51 } 52 53 @Override 54 public boolean equals(Object obj) { 55 if(obj instanceof Employee){ 56 Employee e = (Employee) obj; 57 return super.equals(obj)&& e.getId() == id; 58 } 59 return false; 60 } 61 }
输出结果:
true true false
很不给力嘛,p1竟然等于e1,也等于e2,为什么不是同一个类的两个实例竟然也会相等呢?这很简单,因为p1.equals(e1) 是调用父类Person的equals方法进行判断的,它使用instanceof关键字检查e1是否是Person的实例,由于两者存在继承关系,那结果当然是true了,相等也就没有任何问题了,但是反过来就不成立了,e1或e2可不等于p1,这也是违反对称性原则的一个典型案例。
更玄的是p1与e1、e2相等,但e1竟然与e2不相等,似乎一个简单的等号传递都不能实现。这才是我们要分析的真正重点:e1.equals(e2)调用的是子类Employee的equals方法,不仅仅要判断姓名相同,还要判断工号是否相同,两者工号是不同的,不相等也是自然的了。等式不传递是因为违反了equals的传递性原则,传递性原则是指对于实例对象x、y、z来说,如果x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)也应该返回true。
这种情况发生的关键是父类使用了instanceof关键字,它是用来判断是否是一个类的实例对象的,这很容易让子类“钻空子”。想要解决也很简单,使用getClass来代替instanceof进行类型判断,Person类的equals方法修改后如下所示:
1 public boolean equals(Object obj) { 2 if(obj!=null && obj.getClass() == this.getClass()){ 3 Person p = (Person) obj; 4 if(p.getName()==null || name==null){ 5 return false; 6 }else{ 7 return name.equalsIgnoreCase(p.getName()); 8 } 9 } 10 return false; 11 }
当然,考虑到Employee也有可能被继承,也需要把它的instanceof修改为getClass。总之,在覆写equals时建议使用getClass进行类型判断,而不要使用instanceof。
本文转自SummerChill博客园博客,原文链接:http://www.cnblogs.com/DreamDrive/p/5431603.html,如需转载请自行联系原作者