前言:以前一直不明白,一个类中为什么重写equlas就必须得重写hashCode,今天闲来无事,终于解决迷惑,仅此记录
首先来看hashCode的定义
1.在 Java 应用程序执行期间,只要对象的 equals 比较操作所用的信息没有被修改,那么在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
2.如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。
3.如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法不一定要产生不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。
从这个里面咱们可以得出两个结论:
- 如果两个对象的equals(Object)相等,那么两个对象的hashCode必须相等,
- 如果对象没有修改,则hashCode不会改变。
下面我们来写一个类来看一下
这个是在没有重写equals与hashCode方法的时候
public class TestInterface3 {
/*
* 姓名
*/
private String name;
/*
* 年龄
*/
private Integer agx;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAgx() {
return agx;
}
public void setAgx(Integer agx) {
this.agx = agx;
}
public static void main(String [] args ){
TestInterface3 test = new TestInterface3();
TestInterface3 test1 = new TestInterface3();
test.name="test";
test1.name="test";
test.agx=1;
test1.agx=1;
System.out.println(test1.hashCode()+"---"+test.hashCode());
System.out.println(test1.equals(test));
}
//结果
231685785---114935352
false
明明这两个对象内容一样啊,为什么用equals的结果却是不相同的呢,但结果却验证了上面的两条结论,大家可以看下是不是。
因为咱们没有重写对象的equals方法,则用的是Object中的equals方法,可以看到它也是比较的两个对象的地址,因为==比的就是地址。
//Object源码中equlas方法
public boolean equals(Object obj) {
return (this == obj);
}
Object中hashCode()方法是一个本地方法,具体怎么算出来的hashCode就不知道了,不过想来也是一种固定的机制。
//Object源码中hashCode方法
public native int hashCode();
下面是重写equlas与hashCode
/*
* 姓名
*/
private String name;
/*
* 年龄
*/
private Integer agx;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAgx() {
return agx;
}
public void setAgx(Integer agx) {
this.agx = agx;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TestInterface3 other = (TestInterface3) obj;
if (agx == null) {
if (other.agx != null)
return false;
} else if (!agx.equals(other.agx))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((agx == null) ? 0 : agx.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
public static void main(String [] args ){
TestInterface3 test = new TestInterface3();
TestInterface3 test1 = new TestInterface3();
test.name="test";
test1.name="test";
test.agx=1;
test1.agx=1;
System.out.println(test1.hashCode()+"---"+test.hashCode());
System.out.println(test1.equals(test));
}
//结果
3557490---3557490
true
hashCode与equals都相等,正好验证了上面的两个结论
这也是我们能用String类型调用equals的原因,因为String的源码中也重写了这两个方法,源码如下图
//String源码中hashCode方法
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
//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;
}
如果小伙伴们还不明白的话,可以去看下HashMap的源码看一下是不是能得出两个结论:
- HashCode相同但对象不一定相同
- equals相同则hashCode必须相同