本文共 5447 字,大约阅读时间需要 18 分钟。
首先看一下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 {@codenull} and is a {@code
4 * String} object that represents the same sequence of characters as this5 * object.6 *7 *@paramanObject8 * The object to compare this {@codeString} against9 *10 *@return{@codetrue} if the given object represents a {@codeString}11 * equivalent to this string, {@codefalse} otherwise12 *13 *@see#compareTo(String)14 *@see#equalsIgnoreCase(String)15 */
16 public booleanequals(Object anObject) {17 if (this ==anObject) {18 return true;19 }20 if (anObject instanceofString) {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 packageequals;2
3 import java.time.*;4 importjava.util.Objects;5
6 public classEmployee7 {8 privateString name;9 private doublesalary;10 privateLocalDate hireDay;11
12 public Employee(String name, double salary, int year, int month, intday)13 {14 this.name =name;15 this.salary =salary;16 hireDay =LocalDate.of(year, month, day);17 }18
19 publicString getName()20 {21 returnname;22 }23
24 public doublegetSalary()25 {26 returnsalary;27 }28
29 publicLocalDate getHireDay()30 {31 returnhireDay;32 }33
34 public void raiseSalary(doublebyPercent)35 {36 double raise = salary * byPercent / 100;37 salary +=raise;38 }39
40 public booleanequals(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 inthashCode()59 {60 returnObjects.hash(name, salary, hireDay);61 }62
63 publicString toString()64 {65 return getClass().getName() + "[name=" + name + ",salary=" + salary + ",hireDay=" +hireDay66 + "]";67 }68 }
子类:
1 packageequals;2
3 public class Manager extendsEmployee4 {5 private doublebonus;6
7 public Manager(String name, double salary, int year, int month, intday)8 {9 super(name, salary, year, month, day);10 bonus = 0;11 }12
13 public doublegetSalary()14 {15 double baseSalary = super.getSalary();16 return baseSalary +bonus;17 }18
19 public void setBonus(doublebonus)20 {21 this.bonus =bonus;22 }23
24 public booleanequals(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 inthashCode()33 {34 return super.hashCode() + 17 * newDouble(bonus).hashCode();35 }36
37 publicString toString()38 {39 return super.toString() + "[bonus=" + bonus + "]";40 }41 }
注意:如果重新定义equals方法,就必须重新定义hashCode方法,以便用户可以将对象插入到散列表中。
如果不太懂(4)到底说的是神马,请看以下摘抄的一篇博文的部分内容,对比instanceof和getClass()的区别,其实getClass会判断实例的类是否相等,而instanceof相等的条件,包括两种情况:(1) 类自身 instanceof 类自身;(2) 子类 instanceof 父类;
1 classA { }2
3 class B extendsA { }4
5 Object o1 = newA();6 Object o2 = newB();7
8 o1 instanceof A => true
9 o1 instanceof B => false
10 o2 instanceof A => true //<================ HERE
11 o2 instanceof B => true //<================ HERE
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 //<================ HERE
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