zoukankan      html  css  js  c++  java
  • [改善Java代码]在equals中使用getClass进行类型判断

    建议47: 在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。

  • 相关阅读:
    OCP-1Z0-053-V12.02-367题
    OCP-1Z0-053-V12.02-16题
    OCP-1Z0-053-V12.02-21题
    OCP-1Z0-053-V12.02-368题
    OCP-1Z0-053-V12.02-356题
    VC++ 线程池(h)
    OCP-1Z0-053-V12.02-361题
    OCP-1Z0-053-V12.02-355题
    OCP-1Z0-053-V12.02-289题
    OCP-1Z0-053-V12.02-100题
  • 原文地址:https://www.cnblogs.com/DreamDrive/p/5431603.html
Copyright © 2011-2022 走看看