Object 的 hashCode() 与 equals()
hashCode
public native int hashCode();
原生的 hashCode() 是一个本地方法,返回的是根据物理地址换算出来的一个唯一值。
equals
public boolean equals(Object obj) {
return (this == obj);
}
原生的 equals() 比较的是物理地址是否一样。
重写 equals() 的场景
class Student{
String name;
String nickName;
String age;
//...
}
这里有一个 Student 类,如果我 new 了两个 Student 对象,但它们的属性完全相同。我现在想用 equals() 方法区分它们是不是同一个 Student。
按照 Object 的 equals() 方法的逻辑,它们是不一样的,因为物理地址不同。
但如果按我的逻辑,只要属性一样,就是同一个 Student,如何做到呢?
重写 equals() 方法,我们来看一下用 IDEA 自动生成的 equals()
@Override
public boolean equals(Object o) {
//如果内存地址相同
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Objects.equals(name, student.name) &&
Objects.equals(nickName, student.nickName) &&
Objects.equals(age, student.age);
}
其中,
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
可以看到,只要对应属性的物理地址相同或者,equals 就可以了。而这里,属性都是 String 类型的,String 已经重写了 equals。
String 的 equals()
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
只要2个String的字符串数组里的每个值一样,就 equals。
重写 hashCode() 的场景
在前面重写 equals() 的场景里,完全没看到 hashCode() 的用武之地,那么在什么场景下需要重写它呢?
答案是:与 hash 有关的场景里。如 HashMap。
还是之前的 Student,我现在要统计属性一样的 Student 有多少个。很容易想到,用 HashMap<Student, Integer>。
但是,HashMap 里是这么判断两个 key 是否一样的:
p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k)))
也就是说它们的 hash 值必须一样且key的物理地址一样或 equals。
已经重写了 equals,&& 右边的条件可以满足。
左边的 hash 值是由 hashCode() 计算来的:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
也就是说 hashCode() 不同,hash 就不同,key 就不同。这不是我们想要的。
所以我们需要重写 hashCode(),让属性一样的 Student 的 hashCode() 也一样。看看 IDEA 自动生成的
@Override
public int hashCode() {
return Objects.hash(name, nickName, age);
}
其中,
public static int hash(Object... values) {
return Arrays.hashCode(values);
}
其中,
public static int hashCode(Object a[]) {
if (a == null)
return 0;
int result = 1;
for (Object element : a)
result = 31 * result + (element == null ? 0 : element.hashCode());
return result;
}
让每一个属性参与运算并尽量不发生 hash 冲突(属性不同的 Student,hashCode()一样,就是 hash 冲突)。
213

被折叠的 条评论
为什么被折叠?



