你有没有想过: Java 虚拟机是如何判断两个对象是否相同的?判断的流程是什么?

8次阅读

共计 1974 个字符,预计需要花费 5 分钟才能阅读完成。

在 Java 程序运行时,会产生那么多的对象,那 Java 虚拟机是如何判断两个对象是否相同的呢?判断的流程是什么?
参考解答:Java 虚拟机会先判断两个对象的 hashCode 是否相同,如果 hashCode 不同,则说明肯定是两个不同的对象了;如果 hashCode 相同再通过 equals() 方法进行进一步比较,如果 equals 方法返回 true,则说明两个对象是相同的,如果 equals 方法返回 false 说明两个对象不同。
如何验证
怎么来验证这个问题呢?我们知道 HashSet 是不允许存储相同的键值的。所以我们可以用 HashSet 存储两个相同的键值来模拟,看 Java 虚拟机是如何做判断和识别的,从而验证我们的猜想。
// 先自定义一个类并复写 hashCode 和 equals 方法

public class CustomClass {

@Override
public int hashCode() {
System.out.println(“ 判断 hashCode”);
return 1; // 返回 1,说明所有新建的对象的哈希值都为 1,也就是相同
}

@Override
public boolean equals(Object o) {
System.out.println(“ 判断 equals”);
return true; // 返回 true
}
}
接下来我们用 HashSet 来存储两个自定义的 CustomClass 的对象,代码如下:
public class HashSetTest {
public static void main(String[] args) {

HashSet<CustomClass> hs = new HashSet<>();
CustomClass cs1 = new CustomClass();
CustomClass cs2 = new CustomClass();
hs.add(cs1);
hs.add(cs2);
System.out.println(“—-hs 添加完毕 ”);
System.out.println(“hs:”+hs); // 打印一下 hashSet 集合看里面存放了什么

}
}
打印结果如下:
判断 hashCode
判断 hashCode
判断 equals
—-hs 添加完毕
判断 hashCode // 此处的判断是打印输出语句执行时调用的,与分析本问题无关
hs:[com.alankeene.javalib.collections.CustomClass@1]
结果分析:执行 hs.add(cs1) 语句的时候,Java 虚拟机会先判断 cs1 所指向对象的 hashCode,因为是第一次往 HashSet 集合里面存放元素,该元素 hashCode 在集合中肯定是还没存在的,这是个新的元素,所以直接存放进集合中,不用调用 cs1 所指向对象的 equals 方法。当执行 hs.add(cs2) 语句时,这是第二次往集合里存放元素,有新的元素 cs2 要添加进来,那先要调用 cs2 所指向对象的 hashCode 方法看看它的哈希值是不是与集合中已有元素的哈希值重复了,发现重复了,哈希值都是 1,那有可能是同一个对象,那就要调用 cs2 所指向对象的 equals 方法做进一步判断,发现 equals 方法返回 true,则判断为是重复的元素,就不往集合里添加了。
所以最终打印 HashSet 集合的时候可以看到,集合中只存放了一个元素。
我们再反证一下,把 equals 方法改为返回 false,模拟两个 hashCode 相同,但是是两个不同的对象的情景。
public class CustomClass {

@Override
public int hashCode() {
System.out.println(“ 判断 hashCode”);
return 1; // 返回 1,说明所有新建的对象的哈希值都为 1,也就是相同
}

@Override
public boolean equals(Object o) {
System.out.println(“ 判断 equals”);
return false; // 返回 false
}
}
打印结果会如下:
判断 hashCode
判断 hashCode
判断 equals
—-hs 添加完毕
判断 hashCode // 此处的判断是打印输出语句执行时调用的,与分析本问题无关
判断 hashCode // 此处的判断是打印输出语句执行时调用的,与分析本问题无关
hs:[com.alankeene.javalib.collections.CustomClass@1, com.alankeene.javalib.collections.CustomClass@1]
会发现,HashSet 集合中存放了两个元素了,说明虽然 cs1 和 cs2 的哈希值相同,但是虚拟机判断为不同的元素并存入集合中了。
由此,验证了我们的猜想。Java 虚拟机是先判断 hashCode,如果 hashCode 相同再通过 equals 去判断两个对象是否相同的。

正文完
 0