标签:重写 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
标签:重写 quick imp ... 需要 local 相同 useful 参数
原文地址:https://www.cnblogs.com/llawliet0001/p/10025408.html