第10条:覆盖equals时请遵守通用约定
不需要重写的场景:
- 类的每个实例是唯一的
- 类不需要提供逻辑相等的场景
- 超类已经重写了equals方法
- private类或 缺省类
需要写的规范:
-
自反性,自己必须等于自己
-
对称性,x.equals(y),那么y.equals(x)
-
传递性 ,a.equals(b),b.equals©,那么a.euqals©
-
a,b 没发生变化,那么 a.equals(b) 多次调用后结果也相同
-
对于任何非null值x,必有 x.euqals(y) 为 false;
对称性错误 不能只考虑一边
public class CaseInsensitiveString {
private final String s;
public CaseInsensitiveString(String s) {
this.s = Objects.requireNonNull(s);
}
public boolean euqals(String o) {
if (o.equalsIgnoreCase(s)) {
return true;
} else {
return false;
}
}
public static void main(String[] args) {
CaseInsensitiveString caseInsensitiveString = new CaseInsensitiveString("AAA");
String test = "aaa";
boolean a = caseInsensitiveString.euqals(test);
boolean b = test.equals(caseInsensitiveString.s);
System.out.println(a + " " + b); //true false
}
}
警惕:
- 覆盖equals时总要覆盖hashcode
- 不要企图让equals方法过于智能, 简单点不容易出错
- equals(Object o) 不要写成其他类型的,不然不能重写
第11条:覆盖equals时总要覆盖hashCode
-
equals方法相等时,hashcode必须相等
-
重写hashcode的方法
2.1 先利用基本数据类型的包装类来获取属性的hashcode再进行组合
2.2 结果可以用* 31 来进行相加,选31。31便于移位和减法代替乘法
public class PhoneNumber {
private final short areaCode, prefix, lineNum;
public PhoneNumber(short areaCode, short prefix, short lineNum) {
this.areaCode = areaCode;
this.prefix = prefix;
this.lineNum = lineNum;
}
@Override
public boolean equals(Object o) {
if (o.equals(this)) {
return true;
} else if (!(o instanceof PhoneNumber)) {
return false;
} else {
PhoneNumber phoneNumber = (PhoneNumber) o;
return this.areaCode == phoneNumber.areaCode
&& this.lineNum == phoneNumber.lineNum
&& this.prefix == phoneNumber.prefix;
}
}
@Override
public int hashCode() {
int result = Short.hashCode(areaCode);
result = result * 31 + Short.hashCode(prefix);
result = result * 31 + Short.hashCode(lineNum);
return result;
}
}
第12条 始终要覆盖toString方法
toString方法能够更方便的去返回想要的信息,对对象来说是一个很简洁的说明;
第13条 谨慎地覆盖clone
clone规范:
对于任意对象x
- x.clone() != x 返回true
- x.clone().getClass() == x.getClass() 通常返回true
- x.clone().equals(x) 通常返回true
第14条 考虑实现Comparable接口
- 对称性, x.compareTo(y) == - y.compareTo(x)
- 传递性,x.compareTo(y)>0 y.compareTo(z)>0 则 x.compareTo(z)
- 强烈建议 (x.compareTo(y) ==0 ) == (x.equals(y))
若要实现排序功能,最好实现Comparable接口,避免使用>或<号,应使用包装类的比较方法,或者使用比较器的构造方法
private static final Comparator<PhoneNumber> COMPARATOR = Comparator.comparingInt(((PhoneNumber phoneNumber) -> phoneNumber.areaCode))
.thenComparing(phoneNumber -> phoneNumber.prefix)
.thenComparing(phoneNumber -> phoneNumber.lineNum);