谈一谈HashSet中hashCode的作用. 
说一下我自己的理解. 在存放集合,这种数据的时候,我们可以选择List和Set两种形式,当然,Java当中它们不是具体的实现类.我们可以使用具体的实现类进行数据的存储. 
但是List和Set的最显著区别,应该是,List可以放置相同的元素,Set只能放置不同的元素.也就是说Set里面的元素具有唯一性. 当然ArrayList和LinkedList也只是具体的实现形式不同了.我们也可以实现一个ArraySet或LinkedSet.但是.我们会发现一个比较严重的问题.就是.当我们向ArraySet(或LinkedSet)里面添加元素的时候,我们要逐个比较里面的所有已有元素.这样,当集合中数量非常多的时候,比较次数也会直线上升.也就是说,当我们结合中有10000个元素的时候,我再添加一个元素,要首先比较最多10000次才能确定我要添加的元素是否已经存在了,这会严重影响集合的性能. 为了更快捷的检索数据,我们才引进了hashCode的概念,每个Set里面的元素都会有一个hashCode的值,我们可以按照hashCode的值来存储集合里面的元素.如果要检索集合里面是否存在要添加的元素,只要先将该元素的hashCode值算出来,再到相应的位置进行查找,就可以了.对于相同hashCode的不同元素,我们把这个位置,按照链表的形式进行存放.这样,就可以很大程度上减少比较的次数.举个例子: 我们Set集合里面可能已经10000个不同的元素了.当添加新元素的时候,我们根据新元素的hashCode值,找到相应的位置,这个位置所对应的链表里面,可能只有五个元素,那么,我们只要比较5次,就可以判断整个集合中是否已经存在该元素了,因为,相同元素的hashCode一定是相同的.呵呵.为了使根据hashCode确定位置的速度更快,我们采用数组的下标来表示位置,数组里面存放链表.下标都是自然数,所以,要把hashCode进行向数组下标的映射转换(其实就是与运算). 最后,来谈谈,什么情况下重写hashCode,我们知道,自然情况下,hashCode所产生的值是很有规律的,这样的话,拥有10000个元素的Set,可能有9000个都在同一个位置上,这样,再加一个相同hashCode的元素时,那可能要比较90000次了.所以,我们要自己定义hashCode使得这些元素的hashCode在hashSet里面存储更加分散.不过Java的HashSet里面,已经有一个方法,将元素的hashCode做打散处理了,这个方法对于默认的hashCode还是比较有效果的.对于熟悉这些内容的程序员,为了程序的效率更高,可以重写hashCode方法.但是,不能使用随机数充当hashCode,每个元素,都应该对应唯一的一个hashCode,一个hashCode可以对应多个元素. 引用的一段话.
第四段里:每个Set里面的元素都会有一个hashCode的值,我们可以按照hashCode的值来存储集合里面的元素.如果要检索集合里面是否存在要添加的元素,只要先将该元素的hashCode值算出来,再到相应的位置进行查找,就可以了.对于相同hashCode的不同元素
Set里面会有相同hashCode的元素么?Set里元素值不是唯一的么?会有相当的hashCode?哪位大虾解释一下,有点晕了.还有hashCode()的作用.....

解决方案 »

  1.   

    此回复为自动发出,仅用于显示而已,并无任何其他特殊作用
    楼主【kittaaron】截止到2008-07-23 16:37:33的历史汇总数据(不包括此帖):
    发帖的总数量:1                        发帖的总分数:30                       每贴平均分数:30                       
    回帖的总数量:50                       得分贴总数量:9                        回帖的得分率:18%                      
    结贴的总数量:1                        结贴的总分数:30                       
    无满意结贴数:0                        无满意结贴分:0                        
    未结的帖子数:0                        未结的总分数:0                        
    结贴的百分比:100.00%               结分的百分比:100.00%                  
    无满意结贴率:0.00  %               无满意结分率:0.00  %                  
    敬礼!
      

  2.   

    Java中规定了:如果 a.equals(b),则必然有 a.hashCode() == b.hashCode(),反之不一定成立hashCode的用处是为了方便Set快速的定位
    例如HashSet内部是使用HashMap完成的,而HashMap中内部是用数组存储Entry对象的,就是Entry[] table对象每个Entry是一个链表,有Entry next这个成员
    当我Put一个东西进Map/Set时,首先Java计算这个Key的hashCode,
    然后 hashCode % table.length就可以迅速的定位这个Key可能放在这个table的索引 index
    这样已经可以避免了大量的比较函数了在找到索引后,就开始逐个比较放在index位置的Entry链表,直到找到equals的Key对象或者链表的尾部所以hashCode是为了方便 Map/Set 迅速定位的
    因为Java中的规定:如果 a.equals(b),则必然有 a.hashCode() == b.hashCode();
    所以你只要重写了equals方法,则必须重写hashCode方法
      

  3.   

    首先Java计算这个Key的hashCode, 
    然后 hashCode % table.length就可以迅速的定位这个Key可能放在这个table的索引 index table.length是固定值???如果不是的话,那同样的hashCode % table.lengthr的结果就有可能在不同的table的索引index了。。插进去的话Set里不是有重复值了么!?
      

  4.   

    table.length在一定的时间内当然是固定值,你放入2个还是3个都是相同的值,
    只有当存入的对象数目增多到一定的时候,导致同一个index放入的对象过多,Map/Set才会去放大这个table
    当发生 table.length发生改变的时候,Map/Set会重新计算一次这些Entry应该重新放在哪个索引上,而不是直接放在原来的位置中
      

  5.   

    复写equals方法时最好也把hashCode方法复写
      

  6.   

    我记得有个极限的例子就是所有元素的hashcode都是一样的,这样后果就是往HashMap里存储的时候index都一样,那么就相当于table[]只有1个值,而这个值跟随了一个n个节点的链表,导致HashMap的效率下降到了LinkList了
      

  7.   

    那我引用的那段话里面是不是应该有问题?
    如果查找插入地方时是用hashCode % table.length来算的话。那就是某个值的hashCode设为(aCode)与值为(aCode+table.length) 的元素会放在同一个table[x]中?    而并不是有相同的hashCode的元素才放在同一个table[x]中。  这样理解对不对。
    最后一问了,完了结贴!  感谢6楼
      

  8.   


    没错,的确会放在同一个table[x]中的。所以同一个table[x]中并不是所有的Entry都有相同的hashCode值,因此HashMap在table[x]这个链表中查找的时候首先会判断hashCode是否相等来提高效率: if (e.hash == hash && eq(k, e.key))