Object类提供equals方法,所有的类都继承Object类,也继承它的equals方法,判断类的实例是否与另一个实例相等
覆盖equals的步骤
1. 使用==操作符检查参数是否为这个对象的引用,如果是,则直接返回true;
2. 使用instanceof检查参数是否为正确的类型,如果不是,则直接返回false;
3. 经过第二步检查后,确定参数的类型,将参数转换为正确的类型(记住equals的参数是Object类型,在这一步就可以对参数进行类型转换了);
4. 对对象的每一个关键域,检查参数中对应域是否匹配。
覆盖equals的类必须覆盖hashCode方法,hashCode约定,相等的对象必须具有相等的散列码(hash code)
hashCode约定,(1)如果两个对象x和y满足x.equals(y) == true,它们的散列码应当相同。(2)如果两个对象的hashCode相同,它们并不一定相同。违背了上述原则对于使用哈希存储的系统,如果哈希码频繁的冲突将会造成存取性能急剧下降。
以java.lang.String为例,看一下源码
public boolean equals(Object anObject) {
//1. 首先使用==检查是否为同一对象
if (this == anObject) {
return true;
}
//2. 检查参数类型
if (anObject instanceof String) {
//3. 类型转换
String aString = (String)anObject;
//4. 对对象关键域匹配检查
if (coder() == aString.coder()) { //判断编码格式是否相同
return isLatin1() ? StringLatin1.equals(value, aString.value) //
: StringUTF16.equals(value, aString.value);
}
}
return false;
}
// StringLatin1的equals方法
@HotSpotIntrinsicCandidate
public static boolean equals(byte[] value, byte[] other) {
if (value.length == other.length) {
for (int i = 0; i < value.length; i++) {
// 遍历每个字符
if (value[i] != other[i]) {
return false;
}
}
return true;
}
return false;
}
// StringUTF16的equals方法
@HotSpotIntrinsicCandidate
public static boolean equals(byte[] value, byte[] other) {
if (value.length == other.length) {
// 使用utf-16编码下,一个字符用2个byte来表示,所以除2才是字符个数。
int len = value.length >> 1;
// 遍历每个字符
for (int i = 0; i < len; i++) {
if (getChar(value, i) != getChar(other, i)) {
return false;
}
}
return true;
}
return false;
}
重写了equals方法之后,重写hashcode()方法,保证相同的String对象有相同的hash值
public int hashCode() {
//hash默认为0
int h = hash;
if (h == 0 && value.length > 0) {
//返回特定编码的hash值,有值域value决定,因此可以保证equals的String对象hash相等
hash = h = isLatin1() ? StringLatin1.hashCode(value)
: StringUTF16.hashCode(value);
}
return h;
}
//StringLatin1的hashCode方法
public static int hashCode(byte[] value) {
int h = 0;
for (byte v : value) {
h = 31 * h + (v & 0xff);
}
return h;
}
//StringUTF16的hashCode方法
public static int hashCode(byte[] value) {
int h = 0;
int length = value.length >> 1;
for (int i = 0; i < length; i++) {
h = 31 * h + getChar(value, i);
}
return h;
}
无论何时,equals方法保证以下等价关系
1. 自反性: 对于任何非null的实例x,保证x.equals(x)返回true;
2. 对称性: 对于任何非null的实例x,y,如果x.equals(y)为true,那么y.equals(x)也为true;
3. 传递性: 对于任何非null的实例x,y,z, 如果x.equals(y)为true,y.equals(z)为true,那么x.equals(z)为true;
4. 一致性: 对于任何非null的实例x,y,只要不修改x或y, 那么x.equals(y)一直为true或者一直为false.