今天在学习Java的时候,看到了一道非常有意思的题跟大家分享,顺便记录一下,免得以后忘了
题目出处:韩顺平零基础30天学会Java P552(www.bilibili.com/video/BV1fh411y7R8?p=552)
题目:
Person类有属性id(int)和属性name(String), Person类已按id和name重写了hashcode和equals方法,问以下代码输出什么
HashSet set = new HashSet(); Person p1 = new Person(1001, "AA"); Person p2 = new Person(1001, "BB"); set.add(p1); set.add(p2); p1.name = "CC"; set.remove(p1); System.out.println(set); set.add(new Person(1001, "CC")); System.out.println(set); set.add(new Person(1001, "AA")); System.out.println(set);
输出结果:
[Homework.Person@103a9, Homework.Person@10789]
[Homework.Person@103a9, Homework.Person@10789, Homework.Person@10789]
[Homework.Person@103a9, Homework.Person@10789, Homework.Person@10789, Homework.Person@ffc9]
输出结果分别输出了2 3 4个对象,而我的答案是1 2 3个对象,最终我找到了问题所在,归根结底还是底层机制没学好
图文详解:
前面的代码都没什么大问题
HashSet set = new HashSet(); Person p1 = new Person(1001, "AA"); Person p2 = new Person(1001, "BB"); set.add(p1); set.add(p2);
从这开始就有问题了,这里很容易就会掉进陷阱里
p1.name = "CC"; set.remove(p1); System.out.println(set);
现在假设p1的哈希值为001,哈希运算后在数组的索引为1
现在假设p2的哈希值为002,哈希运算后在数组的索引为2
将p1的name更改为"CC"
现在的p1因为属性变动了,所以哈希值变更为003
set调用remove方法并传入p1,而此时p1的哈希值为003,进行哈希运算后获得的索引为3,而索引为3的位置是空,所以不影响原来的元素
所以输出2个对象
set.add(new Person(1001, "CC")); System.out.println(set);
现在添加一个Person对象, 这个对象的id与name和p1一样,所以哈希运算后的索引也为3,而索引为3上没有元素,所以添加成功
输出3个对象
set.add(new Person(1001, "AA")); System.out.println(set);
接下来又添加了一个Person对象,这个Person对象的属性与最开头的p1一样,所以进行哈希运算后索引为1
但是索引1的位置已经有对象了,所以使用对象的hashcode方法和equals方法进行比较,而新的对象的属性与现在p1的属性不同,所以新的对象会被添加到链表上
最终输出4个对象