黑马程序员技术交流社区
标题:
关于hash值存储的问题
[打印本页]
作者:
刘利民
时间:
2013-7-20 10:22
标题:
关于hash值存储的问题
第三次看毕老师讲解集合中的hashSet时突然想到一个问题:老师说,hashSet底层的数据结构是hash表,而当两具有相同的hash值的,而又不是同一对象的时候,那么这时,元素就会以链的形式在原对象的基础上链接新的对象,问:照这样说,如果我重写了,hashCode方法。并设置为一个固定的值,那么当我存储大量的不相同的对象的时候,那么我可不可把此时底层存储的对象的数据结构看成是链表数据结构?可不可以用链表数据结构的特点来操作底层的元素呢?
作者:
赵太云
时间:
2013-7-20 18:14
其实hashSet集合存储的是对象的引用。如果覆写了hashCode方法,而正真对象的地址的映射得是super.hashCode();
按照你的做法。但是你要知道,hashSet是无序的。也就是说如果要像操作链表一样的话,还是用LinkedList吧!!!
作者:
a767175432
时间:
2013-7-20 19:36
你的想法是正确的,当独享拥有同一hashcode的时候他们会在同一段以hash值标识的内存中以链的形式存放
这样就不是很好了 但是HashSet的性能就是因为底层是使用hash算法来提高性能的
下面是我看完张孝祥老师的高新技术在CSDN上写的博客:
HashSet添加元素的时候会判断是否重复,而判断两个元素重复的条件是它们的equals方法返回true并且hashCode值相等。
在hash算法会将集合来分成一个一个区域的,添加的元素的时候也会计算出hash值来决定将元素放进哪个区域。
例如:区域1. 区域2. 区域3.
如果一个对象只是重写了equals方法并没有重写hashCode方法的时候会出现这么一种情况,如果有一个对象a1 = A(4,5)计算出hashcode被添加进集合区域1中了,另一个对象a2 = A(4,5)再次被添加进集合的时候,可能会计算出hashcode值对应在区域3中,那么它调用equals方法比较区域三中对象时候相同,结果没有相同的,a2成功添加进集合了,这就有问题了,就是因为hash算法是对象只比较自己所在区域的对象,所以我们在写代码的时候会约定当当两个对象的equals方法返回true的时候,他们的hashcode值也应该相等。
加入一个对象添加进入集合当中就不要修改其内部参与计算hashcode的属性了,如果修改了,这个对象就跑到别的内存中了,就删除不掉了,会引发内存泄露。
例如以下代码:
public class Test04
{
public static void main(String[] args)
{
Collection<Point> coll = new HashSet<Point>();
Point p1 = new Point(3, 3);
Point p2 = new Point(4 ,5);
Point p3 = new Point(8 ,9);
coll.add(p1);
coll.add(p2);
coll.add(p3);
p1.y = 8;
coll.remove(p1);
System.out.println(coll.size());
}
}
class Point
{
public int x;
public int y;
public Point(int x,int y)
{
this.x = x;
this.y = y;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Point other = (Point) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
}
复制代码
上述代码将p1,p2,p3加入集合当中,集合大小是3,这里的p1对象添加进集合后被修改了x值导致了p1对象找不到了,remove方法后打印集合的大小还是3,说明p1没有删除成功,导致内存泄露!!
所以楼主思想是对的 就是如果这样做就让HashSet失去了使用的价值了
作者:
肥猫
时间:
2013-7-20 21:16
可以的,不过得搜到这个链表的地址时才采用的,操作从链表头部开始.
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2