黑马程序员技术交流社区

标题: HashSet的取值顺序问题 [打印本页]

作者: 黄玉昆    时间: 2013-2-24 11:23
标题: HashSet的取值顺序问题
本帖最后由 黄玉昆 于 2013-2-24 13:00 编辑

毕老师在将HashSet的时候,说存入顺序是按照哈希值的顺序存入的,是不是按照哈希值的大小进行依次排列的呢?那读取也应该是按照存入的顺序或者倒叙取出的才对,我不知道这样理解是不是正确的。
如果不是的话,是具体按什么顺序存的呢?如果是这样的话,那么为什么我反复测试,都不是按大小顺序取出的呢?
测试如下:
  1. <font size="1" face="Arial">import java.util.*;

  2. class Person
  3. {
  4.         private String name;
  5.         private int age;
  6.         Person(String name,int age)
  7.         {
  8.                 this.name = name;
  9.                 this.age = age;
  10.         }
  11.         public String getName()
  12.         {
  13.                 return name;
  14.         }
  15.         public int getAge()
  16.         {
  17.                 return age;
  18.         }
  19.         public int hashCode()
  20.         {
  21.                 //System.out.println(this.name + "--hashCode--");
  22.                 System.out.println(this.name + "--" + (this.name.hashCode()+age*39));
  23.                 return this.name.hashCode()+age*39;
  24.         }
  25.         public boolean equals(Object obj)
  26.         {
  27.                 if (!(obj instanceof Person))
  28.                         return false;
  29.                 Person p = (Person)obj;
  30.                 //System.out.println(this.name + "--equals--" + p.name);
  31.                 return this.name.equals(p.name) && this.age == p.age;
  32.         }
  33. }
  34. class HashTest
  35. {
  36.         public static void sop(Object obj)
  37.         {
  38.                 System.out.println(obj);
  39.         }

  40.         public static void main(String[] args)
  41.         {
  42.                 HashSet hs = new HashSet();
  43.                 hs.add(new Person("a1",11));
  44.                 hs.add(new Person("a2",12));
  45.                 hs.add(new Person("a3",13));
  46.                 hs.add(new Person("a2",12));
  47.                 hs.add(new Person("a3",13));

  48.                 Iterator it = hs.iterator();

  49.                 while (it.hasNext())
  50.                 {
  51.                         Person p = (Person)it.next();
  52.                         sop("-------");
  53.                         sop(p);
  54.                         sop(p.getName() + "--" + p.getAge());
  55.                 }
  56.         }
  57. }</font>
复制代码
结果如图:


哈希值测试图.png (2.2 KB, 下载次数: 110)

哈希值测试图.png

作者: 逍林游    时间: 2013-2-24 11:30
HashSet里面的元素是无序(数据添加顺序),并不是照哈希值的大小进行依次排列,只是里面元素对象唯一,这需要重写hashcode()和equals()方法。
只有TreeSet才会按对象大小顺序排列输出,只要对象实现compareable接口,重写compareTo方法就可实现。
作者: 谢波    时间: 2013-2-24 11:35
标题: 在张老师的
本帖最后由 谢波 于 2013-2-24 11:36 编辑

HashSet存储对象是根据对象的hashCode做取模运算,然后根据不同的结果存入不同的区间
所以HashSet是无序的
在张老师的高新技术里面有讲到,去看看吧
作者: 胥文    时间: 2013-2-24 12:02
本帖最后由 胥文 于 2013-2-24 12:05 编辑

HashSet集合底层是哈希表数据结构,所以是集合里面的元素是按哈希值来排序的
为了便于观看,假如你在复写hashcode的方法的时候按年龄来计算
public int hashCode()
{
           return this.age;
}
如果想上面这面写hashcode,你在看你打印的元素是不是有按年龄在排//这样写只是便于直观的看
作者: 黄玉昆    时间: 2013-2-24 12:14
胥文 发表于 2013-2-24 12:02
HashSet集合底层是哈希表数据结构,所以是集合里面的元素是按哈希值来排序的
为了便于观看,假如你在复写ha ...

确实是,打印的结果是按年龄大小打印了,但是这样的话,年龄相同的还要调用equals方法,效率不高啊。我的意思是为什么打印的哈希值并没有按顺序排列。难道哈希值不是按照数值的大小排列的吗?如果是,为什么不按顺序读取呢?
作者: 黄玉昆    时间: 2013-2-24 12:16
逍林游 发表于 2013-2-24 11:30
HashSet里面的元素是无序(数据添加顺序),并不是照哈希值的大小进行依次排列,只是里面元素对象唯一,这 ...

童鞋,我明白这个集合中的元素是无序的,这是因为分配给对象的哈希值是随机的,不是按顺序分配的哈希值,但是哈希值是有序的啊,为什么读取的时候没有按哈希值的顺序读取呢?我要问的是这个意思。不是说为什么不按元素的顺序读取。
作者: 黄玉昆    时间: 2013-2-24 12:17
谢波 发表于 2013-2-24 11:35
HashSet存储对象是根据对象的hashCode做取模运算,然后根据不同的结果存入不同的区间
所以HashSet是无序的
...

谢谢,我理解为什么这个集合是无序的,只是不理解为什么不按哈希值的大小顺序读取,我上面的图中显示的很清楚了。只是这点我不太明白而已
作者: 柴乔军    时间: 2013-2-24 12:17
存入的时候是按照计算出的hashcode值来进行存储,这个无序没什么可说的,但是存入后,位置就会固定了,可当我们取出操作时,每次取出的顺序都不一样

这说明取出也是无序进行操作的,底层如何实现的鄙人也不清楚,楼主如果有相关资料~还请分享下哈
作者: 黄玉昆    时间: 2013-2-24 12:19
柴乔军 发表于 2013-2-24 12:17
存入的时候是按照计算出的hashcode值来进行存储,这个无序没什么可说的,但是存入后,位置就会固定了,可当 ...

好的,我有相关的资料会在这里告诉大家的。谢谢你
作者: 陈科宇    时间: 2013-2-24 12:29
玉昆,按hashCode存储,其实就是散列存储,实质是没有顺序的,这也是Set设计的原意。Hash算法是根据元素的hashCode值来决定元素的存储位置。在查找某个元素时,也是根据hashCode值来查找其内存地址。
作者: 陈科宇    时间: 2013-2-24 12:31
HashSet存储的类型对象,要求是要正确重写equals方法和hashCode方法的。只有这两个方法保持一致,在存取是才不会发生混乱的情形。你可以好好看看这两个方法的重写规则。
作者: 胥文    时间: 2013-2-24 14:02
黄玉昆 发表于 2013-2-24 12:14
确实是,打印的结果是按年龄大小打印了,但是这样的话,年龄相同的还要调用equals方法,效率不高啊。我的 ...

建议你把取出来的集合元素的hashcode比较一下大小,看这样行不行




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2