@SuppressWarnings({"all"}) public class Homework06 { public static void main(String[] args) { //第一部分 HashSet hashSet = new HashSet(); Person p1 = new Person(1001, "AA"); Person p2 = new Person(1002, "BB"); hashSet.add(p1); hashSet.add(p2); System.out.println(hashSet); //第二部分 p1.name = "CC"; System.out.println(hashSet); //第三部分 hashSet.remove(p1); System.out.println(hashSet); //第四部分 hashSet.add(new Person(1001, "CC")); System.out.println(hashSet); //第五部分 hashSet.add(new Person(1001, "AA")); System.out.println(hashSet); } } class Person { private int id; String name; public Person(int id, String name) { this.id = id; this.name = name; } //重写equals和hashCode方法 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return id == person.id && Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(id, name); } @Override public String toString() { return "Person{" + "id=" + id + ", name='" + name + '\'' + '}'; }
运行结果:
[Person{id=1002, name='BB'}, Person{id=1001, name='AA'}] [Person{id=1002, name='BB'}, Person{id=1001, name='CC'}] [Person{id=1002, name='BB'}, Person{id=1001, name='CC'}] [Person{id=1002, name='BB'}, Person{id=1001, name='CC'}, Person{id=1001, name='CC'}] [Person{id=1002, name='BB'}, Person{id=1001, name='CC'}, Person{id=1001, name='CC'}, Person{id=1001, name='AA'}]
HashSet hashSet = new HashSet(); Person p1 = new Person(1001, "AA"); Person p2 = new Person(1002, "BB"); hashSet.add(p1); hashSet.add(p2);
集合结构简图:
p1.name = "CC"; System.out.println(hashSet);
由于hashSet里面存储的key和p1都指向同一块堆空间,所以p1修改了堆空间里的数据,hashSet也会修改,将AA替换为CC。
结构图:
hashSet.remove(p1); System.out.println(hashSet);
分析:在table中,此时指向CC所在的堆空间的key还是存储在table原来的位置(即用"AA和1001"计算hashCode得到的hash值所在的位置)。当使用p1作为键删除对象时,也需要计算hash值来定位待删除元素在table中存储的位置,用修改后的"CC和1001"计算的hashCode值来计算hash值就不是table中原来的位置(用"AA和1001"计算得到),所以不会删除CC,相当于CC占了AA位置,偷天换日。
// hashSet.add(new Person(1001, "CC")); //加入成功 System.out.println(hashSet);
分析:因为现在hashSet的table里存储"1001和CC"的位置是用"1001和AA"计算得到的,所以当新插入的数据用“1001和CC”计算存储位置时,不会判定为重复数据,因为虽然数据内容一样,但是hash值不一样。
注:绿色为新插入的对象。
hashSet.add(new Person(1001, "AA")); System.out.println(hashSet);
分析:此时用“1001和AA”计算得到的存储位置与指向“1001和CC”的key的位置一样(hash值一样),再比较数据,发现AA和CC不算重复,数据内容不同,因此将新的结点可以添加成功。
根据HashSet判断重复的方法,先比较hash值,再比较内容。所以只需要hash值不同就可以存储相同内容,本文所用方法为偷天换日。
注:HashSet判断重复的方法详解链接