为什么java类WeakReference不会覆盖hashcode和equals

时间:2017-02-05 14:31:46

标签: java weak-references

我希望WeakReference类覆盖hashCode并等于像这样的方法

class WeakReference<T>{
  T ref;

  int hashCode(){
    return ref.hashCode();
  }

  boolean equals(Object o){
    return ref.equals(o);
  }
}

这样我就可以直接使用We WeakReference作为

等散列图中的关键字
Person p1 = new Person("p1");
WeakReference<Person> wr = new WeakReference<Person>(p1);

map.put(wr, "some value object");

但是当我测试时,我发现hashCode和equals没有被覆盖

Person p1 = new Person("p1");
WeakReference<Person> wr = new WeakReference<Person>(p1);
WeakReference<Person> wr2 = new WeakReference<Person>(p1);

System.out.println(wr.hashCode()); // prints x
System.out.println(wr2.hashCode()); // prints y

System.out.println(wr.equals(wr2)); // prints false

在WeakReference类中没有覆盖hashCode和equals的任何特定原因?

2 个答案:

答案 0 :(得分:4)

Map上的任何键(或Set的元素)的一个重要方面是,一旦将其添加到集合中,它必须是不可变的(或至少不会更改)。更改密钥具有未定义的行为,这种行为极不可行。

WeakReference可以随时更改,因为执行了GC,即无法控制,这使得equals / hashCode不适合使用这些的一般集合。

  

我试图制作MyWeakConcurrentHashMap

这样做的一个简单方法是使用WeakHashMaps数组。例如32个分区。使用hashCode()来确定要使用的WeakHashMap。这样你就可以让一个线程一次访问每个WeakHashMap(最好的情况)

由于您有更多的并发性,您可以增加分区数。

答案 1 :(得分:0)

似乎 WeakHashMap 使用 Entry 扩展 WeakReference
并覆盖 hashCodeequals
您可以查看它们的实现。

  /**
     * The entries in this hash table extend WeakReference, using its main ref
     * field as the key.
     */
    private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
        V value;
        final int hash;
        Entry<K,V> next;

        /**
         * Creates new entry.
         */
        Entry(Object key, V value,
              ReferenceQueue<Object> queue,
              int hash, Entry<K,V> next) {
            super(key, queue);
            this.value = value;
            this.hash  = hash;
            this.next  = next;
        }

        @SuppressWarnings("unchecked")
        public K getKey() {
            return (K) WeakHashMap.unmaskNull(get());
        }

        public V getValue() {
            return value;
        }

        public V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }

        public boolean equals(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
            K k1 = getKey();
            Object k2 = e.getKey();
            if (k1 == k2 || (k1 != null && k1.equals(k2))) {
                V v1 = getValue();
                Object v2 = e.getValue();
                if (v1 == v2 || (v1 != null && v1.equals(v2)))
                    return true;
            }
            return false;
        }

        public int hashCode() {
            K k = getKey();
            V v = getValue();
            return Objects.hashCode(k) ^ Objects.hashCode(v);
        }

        public String toString() {
            return getKey() + "=" + getValue();
        }
    }