本帖最后由 Neverbelazy 于 2013-5-21 00:40 编辑
这是一个非常好的问题, 不得不说,回答这个问题, 让我学到了很多,楼主的思考很犀利!
我查了一些资料, 大概觉得这么解释比较合理:
1. HashSet底层是HashMap实现的, 其中 HashSet<E> 就是 HashMap里面的键值HashMap<E,Object>; 这个Object是什么都可以,因为我们不会用到
源代码:- // 底层使用HashMap来保存HashSet中所有元素
- private transient HashMap<E,Object> map;
- // 定义一个虚拟的Object对象作为HashMap的value,将此对象定义为static final
- private static final Object PRESENT = new Object();
复制代码 参考1-HashSet源码说明: http://wenku.baidu.com/view/0199f0ef81c758f5f61f6757.html
2. 而HashMap的底层是以键值对-Entry的形式存在的,而关键就在这里,
3. Entry 是一个接口, Map.Entry是一个内部接口, Entry<K,V> 是内部实现类对象的引用名, 其对象是 Map 进行put(K,V)操作时新生产的, Map的比较性是Entry的hashCode决定的
4. 这个对象中, K,V都是引用的传入K,V的地址以索引对象, 可是,Entry的hashCode 这个 int基本类型, 是以值传递的方式将K的hashCode传进来 int hash=K.hashCode(); 然后 Entry的 hashCode()函数再 return hash; 值——在内部被 记录死了
5. 所以, Entry的比较性,是在你放入Map元素的时候就被定死的了, 之后再怎么在 外边该 pt1的hashCode值,也影响不了Entry里面的和pt1对应的Entry<K,V>的hashCode值
6. 所以, 当你remove的时候,是将 K.hashCode 和 相应的 Entry.hashCode()比较; 因为后期 y=7; 所以调用时, 这两个 hashCode()值 不一致了,就无法 移除—— size =2
7. 所以,K是引用传递, Entry中只记录了一个地址, 所以你用 打印集合中的元素时,还是会通过索引找到相应的 pt1 最新的值 ——也就打印了 3:7
参考2: HashMap源码说明 http://wenku.baidu.com/view/ef2d11d449649b6648d747a9.html
总结:
1. HashSet<K> 实现于 HashMap<K,V>
2. HashMap 的比较性是内部Entry的HashCode决定的
3. Entry的 hashCode()值 是值传递 等于 put(K,V)时 K的 hashCode(); 无法再改变
4. K 是引用 传递, 索取地址可以 得到 最新的成员变量值 |