“hashSet存储时,当哈希值相同时,会比较地址值”这是谁告诉你的,太坑了。当 hash 相等时,会使用 equals 方法比较两个元素是否相等,具体 equals 比的是什么,要看具体的实现,在Object 类中提供的基本实现是比较 reference 的值,也就是所谓的“地址值”。hash 值也是同样的道理,具体某对象的 hash 值是怎么算出来的,取决于它所属类型对 hashCode 方法的具体实现。相同 hash 值怎样处理,你可以去找任何一本讲算法和数据结构基础的书来看。

解决方案 »

  1.   

    你可以到源代码中看一下,HashSet的add方法是通过HashMap的put方法实现的,代码如下:
    HashSet的add方法:public boolean add(E e) {
            return map.put(e, PRESENT)==null;
        }
    HashMap的put方法:public V put(K key, V value) {
            if (key == null)
                return putForNullKey(value);
            int hash = hash(key);
            int i = indexFor(hash, table.length);
            for (Entry<K,V> e = table[i]; e != null; e = e.next) {
                Object k;
                if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                    V oldValue = e.value;
                    e.value = value;
                    e.recordAccess(this);
                    return oldValue;
                }
            }        modCount++;
            addEntry(hash, key, value, i);
            return null;
        }仔细看看当hash值相同的时候,底层是如何做的,在代码中体现得很明白了
      

  2.   

    仅通过Java代码是不可能获得对象的地址值的吧~ 事实上哈希值和地址值毫无关系。哈希还会有冲突,LZ觉得地址还能冲突吗?
      

  3.   

    我有点明白LZ被灌输的是个什么东西了,其实lz没有表述清楚,或者根本理解错了。
    首先我们假定有个固定大小的数组,假设他的下标是0-n,那么LZ所说的地址可以认为是这下标0-n。
    说到哈希值,就不得不提到哈希函数。哈希函数是这样一个函数,输入一个可能很巨大的哈希值,出来的是个足够小的,在此例中,范围是0-n的数。另外对于随机的哈希值,输出的数在0-n上我们期望它们出现的概率是平均的。这样只要有一个哈希值,我们通过哈希函数,就能极快地得到一个合法的下标。但凡事总有万一,两个哈希值通过哈希函数很可能对应到同一个下标,这就叫冲突。为了解决冲突,我们在数组上不是直接存放元素,而是存放一个链表,若有冲突,那只能遍历这个链表来得到我们想取得的值了。万幸的是只要哈希函数设得好,数组弄得够大,冲突的概率是比较低的。