在equals中使用getClass进行类型判断

简介:

本节我们继续讨论覆写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,如需转载请自行联系原作者

相关文章
|
8月前
|
存储 Java 程序员
equals方法深入解析
equals方法深入解析
144 0
|
2月前
equals
==是进行对象的地址值比较,如果确实需要字符串的内容比较,可以使用两个方法 public boolean equals(0bjectobj):参数可以是任何对象,只有参数是一个字符串并且内 容相同的才会给true;否则返回false 注意事项: 1.任何对象都能用object进行接收。 2.equals方法具有对称性,也就是a.equals(b)和b.equals(a)效果一样。 3.如果比较双方一个常量一个变量,推荐把常量字符串写在前面。 推荐:"abc".equals(str) 不推荐:str.equals("abc") public boolean egualsIgnoreCas
20 4
|
存储 Java
详解“==”和equals的区别
“==”和equals 最大的区别是 “==”是运算符,如果是基本数据类型,则比较存储的值;如果是引用数据类型,则比较所指向对象的地址值。 equals是Object的方法,比较的是所指向的对象的地址值,一般情况下,重写之后比较的是对象的值。
|
存储 Java
“==”和equals 最大的区别
“==”和equals 最大的区别是 “==”是运算符,如果是基本数据类型,则比较存储的值;如果是引用数据类型,则比较所指向对象的地址值。 equals是Object的方法,比较的是所指向的对象的地址值,一般情况下,重写之后比较的是对象的值。
|
存储
==与equals方法的区别
==操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量的引用地址是否相等,只能用==操作符。
102 0
|
存储
"=="和 equals 方法究竟有什么区别?
"=="和 equals 方法究竟有什么区别?
96 0
|
算法 安全 Java
@EqualsAndHashCode - 相等更简单:从对象的字段生成hashCode和equals实现
@EqualsAndHashCode - 相等更简单:从对象的字段生成hashCode和equals实现
|
存储 NoSQL
简单讲一下 HashCode() 与 equals()方法
简单讲一下 HashCode() 与 equals()方法.
88 0
Object类的toString和Equals方法,以及Objects类的Equals方法
Object类 toString()方法 public class Person { private String name; private int age; public Person() { } public Person(String name, int age) { this.name =