看了韩顺平老师的视频获益匪浅,但是这里有点不太懂,希望会的大神能帮助解答一下。第二次输出前的:set.add(new Person(1001,“CC”));为啥能add进HashSet中这里我很疑惑,自己看了源码打了断点还是有一些疑问,希望能帮我解答一下。自己仿照幻灯片的示例敲了一下代码。
package com.HomeWork;
import org.junit.Test;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Objects;
import java.util.TreeSet;
/**
* @author 心向阳光的天域
* @date 2022/10/10 17:56
*/
public class HomeWork06 {
@Test
@SuppressWarnings({"all"})
public void getHomeWork06() {
People p1 = new People("1001", "AA");
People p2 = new People("1002", "BB");
HashSet hashSet = new HashSet();
hashSet.add(p1);
hashSet.add(p2);
System.out.println("正常情况" + p1.hashCode()); //
p1.name = "CC"; // 因为重写了hashCode,所以name变了之后hash值就会变
System.out.println("修改p1为CC后:" + p1.hashCode()); //
hashSet.remove(p1); // hash值变了之后,删除就找不到以前的p1了
System.out.println("----第一次输出----");
System.out.println(hashSet);
People p3 = new People("1001", "CC"); // hashCode:
System.out.println("p3的hashCode值:" + p3.hashCode()); //
hashSet.add(p3); // 为啥这里add可以插进去?????????
System.out.println("----第二次输出----");
System.out.println(hashSet);
hashSet.add(new People("1001", "AA")); // 这次
System.out.println("----第三次输出----");
System.out.println(hashSet);
}
class People {
private String id;
public String name;
public People(String id, String name) {
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
People people = (People) o;
return Objects.equals(id, people.id) && Objects.equals(name, people.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
@Override
public String toString() {
return "People{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
这里可以明显看到p1对象的hashCode和p3的hashCode一样。但是Debug之后出现了如下图的情况:
这里可以看到绿框框起来的p1对象和p3对象name对应的hash值是完全一样的,但是红框里的hashCode值又不一样,于是我追了一下源码看了看红框里hash值的计算规则。
如下代码所示:
hashSet.add(p3); // 主要是add代码追进源码看
//源码HashMap.class中
//static class Node<K, V> implements Entry<K, V>
Node(int var1, K var2, V var3, HashMap.Node<K, V> var4) {
this.hash = var1; // 这里就是红框中的hash值
this.key = var2;
this.value = var3;
this.next = var4;
}
// 而这里的var1也可以追溯源码HashMap.class中put方法
public V put(K var1, V var2) {
return this.putVal(hash(var1), var1, var2, false, true); // 这里可以看到Node的var1是来自add对象的hash方法
}
// 继续往下看hash方法的计算
static final int hash(Object var0) { // 这里var0就是add后对象p3
int var1;
return var0 == null ? 0 : (var1 = var0.hashCode()) ^ var1 >>> 16; // 这里p1和p3的hashCode相同,为什么最后出来的红框中hash值却不同
}
问题就是最后跟到源码,发现hash值的计算规则,就是分别拿p1和p3的哈希值进行按位与操作,这里是真的不懂为什么红框里计算出来的hash值为什么会不同,以及怎么理解这里能add进去的问题,希望会的大神能帮助解决一下我的困难,感谢。