码迷,mamicode.com
首页 > 编程语言 > 详细

完美重写Java的equals函数

时间:2018-11-27 12:23:47      阅读:263      评论:0      收藏:0      [点我收藏+]

标签:重写   quick   imp   ...   需要   local   相同   useful   参数   

首先看一下String的equals()函数的重写:

 1 /**
 2      * Compares this string to the specified object.  The result is {@code
 3      * true} if and only if the argument is not {@code null} and is a {@code
 4      * String} object that represents the same sequence of characters as this
 5      * object.
 6      *
 7      * @param  anObject
 8      *         The object to compare this {@code String} against
 9      *
10      * @return  {@code true} if the given object represents a {@code String}
11      *          equivalent to this string, {@code false} otherwise
12      *
13      * @see  #compareTo(String)
14      * @see  #equalsIgnoreCase(String)
15      */
16     public boolean equals(Object anObject) {
17         if (this == anObject) {
18             return true;
19         }
20         if (anObject instanceof String) {
21             String anotherString = (String)anObject;
22             int n = value.length;
23             if (n == anotherString.value.length) {
24                 char v1[] = value;
25                 char v2[] = anotherString.value;
26                 int i = 0;
27                 while (n-- != 0) {
28                     if (v1[i] != v2[i])
29                         return false;
30                     i++;
31                 }
32                 return true;
33             }
34         }
35         return false;
36     }

分析一下上面equals()函数:
(1) 首先比较两个对象的引用是否相等,如果两个引用相等,那么两个对象必然相等。

(2) 其次判断anObject是否是String的一个实例 (instanceof关键字的作用是测试一个对象是否是一个类的实例),如果不是则返回false,如果是,则判断obObject的字符串内容是否和this相同:长度是否相等,内容是否相等。

ps: 使用instanceof关键字的问题:当类A是类B的子类时,使用instanceof关键字重写equals()函数就会不符合java语言规范要求equals()方法的“对称性”特性的要求。对称性(对于任何引用x,y,当且仅当y.equals(x)返回true, x.equals(y)也应该返回true)。

一般我们在设计一个类时,需要重写父类的equals方法,在重写这个方法时,需要按照以下几个规则设计:
(1) 自反性:对任意引用值x,x.equals(x)的返回值一定为true.
(2) 对称性:对于任何引用值x,y,当且仅当y.equals(x)返回值为true时,x.equals(y)的返回值一定为true;
(3) 传递性:如果x.equals(y)=true, y.equals(z)=true,则x.equals(z)=true
(4) 一致性:如果参与比较的对象没任何改变,则对象比较的结果也不应该有任何改变
(5) 非空性:任何非空的引用值X,x.equals(null)的返回值一定为false
那么如何编写一个完美的equals方法呢?

(1)显式参数命名为otherObject,稍后需要将它转换成另一个叫做other的变量。

(2)检测this与otherObject是否引用同一个对象:

 if(this == otherObject) return true; 

(3)检测otherObject是否为null,如果为null,返回false:

 if(otherObject == null) return false; 

(4)比价this与otherObject是否属于同一个类。

如果equals的语义在每个子类中有所改变,就使用getClass检测 : if(getClass() != otherObject.getClass()) return false;  

如果所有的子类都拥有统一的语义,就使用instanceof检测 : if(!(otherObject instanceof ClassName)) return false; 

(5) 将otherObject转换为相应的类类型变量:

 ClassName other = (ClassName) otherObject; 

(6)现在开始对所有需要比较的域进行比较 。使用==比较基本类型域,使用equals比较对象域。如果所有的域都匹配,就返回true,否则就返回flase。

 return field1 == other.field1 && Objects.equals(field2,other.field2) && ...; 

(7)如果在子类中重新定义equals,就要在其中包含调用 super.equals(other) 

举例(摘自Java核心技术)

父类:

 1 package equals;
 2 
 3 import java.time.*;
 4 import java.util.Objects;
 5 
 6 public class Employee
 7 {
 8    private String name;
 9    private double salary;
10    private LocalDate hireDay;
11 
12    public Employee(String name, double salary, int year, int month, int day)
13    {
14       this.name = name;
15       this.salary = salary;
16       hireDay = LocalDate.of(year, month, day);
17    }
18 
19    public String getName()
20    {
21       return name;
22    }
23 
24    public double getSalary()
25    {
26       return salary;
27    }
28 
29    public LocalDate getHireDay()
30    {
31       return hireDay;
32    }
33 
34    public void raiseSalary(double byPercent)
35    {
36       double raise = salary * byPercent / 100;
37       salary += raise;
38    }
39 
40    public boolean equals(Object otherObject)
41    {
42       // a quick test to see if the objects are identical
43       if (this == otherObject) return true;
44 
45       // must return false if the explicit parameter is null
46       if (otherObject == null) return false;
47 
48       // if the classes don‘t match, they can‘t be equal
49       if (getClass() != otherObject.getClass()) return false;
50 
51       // now we know otherObject is a non-null Employee
52       Employee other = (Employee) otherObject;
53 
54       // test whether the fields have identical values
55       return Objects.equals(name, other.name) && salary == other.salary && Objects.equals(hireDay, other.hireDay);
56    }
57 
58    public int hashCode()
59    {
60       return Objects.hash(name, salary, hireDay); 
61    }
62 
63    public String toString()
64    {
65       return getClass().getName() + "[name=" + name + ",salary=" + salary + ",hireDay=" + hireDay
66             + "]";
67    }
68 }

子类:

 1 package equals;
 2 
 3 public class Manager extends Employee
 4 {
 5    private double bonus;
 6 
 7    public Manager(String name, double salary, int year, int month, int day)
 8    {
 9       super(name, salary, year, month, day);
10       bonus = 0;
11    }
12 
13    public double getSalary()
14    {
15       double baseSalary = super.getSalary();
16       return baseSalary + bonus;
17    }
18 
19    public void setBonus(double bonus)
20    {
21       this.bonus = bonus;
22    }
23 
24    public boolean equals(Object otherObject)
25    {
26       if (!super.equals(otherObject)) return false;
27       Manager other = (Manager) otherObject;
28       // super.equals checked that this and other belong to the same class
29       return bonus == other.bonus;
30    }
31 
32    public int hashCode()
33    {
34       return super.hashCode() + 17 * new Double(bonus).hashCode();
35    }
36 
37    public String toString()
38    {
39       return super.toString() + "[bonus=" + bonus + "]";
40    }
41 }

注意:如果重新定义equals方法,就必须重新定义hashCode方法,以便用户可以将对象插入到散列表中。

如果不太懂(4)到底说的是神马,请看以下摘抄的一篇博文的部分内容,对比instanceof和getClass()的区别,其实getClass会判断实例的类是否相等,而instanceof相等的条件,包括两种情况:(1) 类自身 instanceof 类自身;(2) 子类 instanceof 父类;

 1 class A { }  
 2  
 3 class B extends A { }  
 4  
 5 Object o1 = new A();  
 6 Object o2 = new B();  
 7  
 8 o1 instanceof A => true  
 9 o1 instanceof B => false  
10 o2 instanceof A => true // <================ HERE  
11 o2 instanceof B => true // <span style="font-family: Arial, Helvetica, sans-serif;"><================ HERE  </span>
12  
13 o1.getClass().equals(A.class) => true  
14 o1.getClass().equals(B.class) => false  
15 o2.getClass().equals(A.class) => false // <===============HERE  
16 o2.getClass().equals(B.class) => true <span style="font-family: Arial, Helvetica, sans-serif;"> // </span><span style="font-family: Arial, Helvetica, sans-serif;"><================ HERE  </span>
17  
18  
19  
20 getClass() will be useful when you want to make sure your instance is NOT a subclass of the class you are comparing with.

参考博客:https://blog.csdn.net/wu_cai_/article/details/51989033

完美重写Java的equals函数

标签:重写   quick   imp   ...   需要   local   相同   useful   参数   

原文地址:https://www.cnblogs.com/llawliet0001/p/10025408.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!