相关的知识,Java 中的四种引用类型。
[[.【自动内存管理-GC理论】Java中的引用]]

WeakHashMap特性

WeakHashMap 是使用弱键的动态散列表,用于实现 “自动清理” 的内存缓存。

  • 1、WeakHashMap 使用与 Java 7 HashMap 相同的 “数组 + 链表” 解决散列冲突,发生散列冲突的键值对会用头插法添加到单链表中;

  • 2、WeakHashMap 依赖于 Java 垃圾收集器自动清理不可达对象的特性。当 Key 对象不再被持有强引用时,垃圾收集器会按照弱引用策略自动回收 Key 对象,并在下次访问 WeakHashMap 时清理全部无效的键值对。因此,WeakHashMap 特别适合实现 “自动清理” 的内存活动缓存,当键值对有效时保留,在键值对无效时自动被垃圾收集器清理;

  • 3、需要注意,因为 WeakHashMap 会持有 Value 对象的强引用,所以在 Value 对象中一定不能持有 key 的强引用。否则,会阻止垃圾收集器回收 “本该不可达” 的 Key 对象,使得 WeakHashMap 失去作用。

  • 4、与 HashMap 相同,LinkedHashMap 也不考虑线程同步,也会存在线程安全问题。可以使用 Collections.synchronizedMap 包装类,其原理也是在所有方法上增加 synchronized 关键字。

    弱引用代码

    //Entry 是键值对中的实体
    private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {  
    V value;  
    final int hash;  
    Entry<K,V> next;  
    
    Entry(Object key, V value,  
          ReferenceQueue<Object> queue,  
          int hash, Entry<K,V> next) {  
        //👉虽然Entry继承于WeakReference,但是只有key继承了弱引用
        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();  
    }  
    }

    WeakHashMap和HashMap的区别

WeakHashMap 与 HashMap 都是基于分离链表法解决散列冲突的动态散列表,两者的主要区别在 键 Key 的引用类型上:

  • HashMap 会持有键 Key 的强引用,除非手动移除,否则键值对会长期存在于散列表中;
  • WeakHashMap 只持有键 Key 的弱引用,当 Key 对象不再被外部持有强引用时,键值对会被自动被清理。

WeakHashMap 与 LinkedHashMap 都有自动清理的能力,两者的主要区别在于 淘汰数据的策略上:

  • LinkedHashMap 会按照 FIFO 或 LRU 的策略 “尝试” 淘汰数据,需要开发者重写 removeEldestEntry() 方法实现是否删除最早节点的判断逻辑;
  • WeakHashMap 会按照 Key 对象的可达性淘汰数据,当 Key 对象不再被持有强引用时,会自动清理无效数据。

使用场景

  1. 缓存场景: 当需要实现缓存功能时,如果使用 WeakHashMap,当某个键对象不再被其他部分引用时,该键值对将被自动移除。这样可以避免内存泄漏,因为不再有强引用指向这个键时,这个键值对会被垃圾回收。

  2. 对象关联场景: 在某些情况下,当一个对象被垃圾回收时,相关的映射关系也应该被移除。WeakHashMap 可以自动处理这种情况,确保映射关系与键对象的生命周期保持一致。

  3. 监听器管理: 在一些事件监听器的管理中,使用 WeakHashMap 可以确保当某个对象不再被引用时,与之相关的监听器也会被正确地移除,防止潜在的内存泄漏。

需要注意的是,由于弱引用的特性,WeakHashMap 的性能可能相对较低,因为在内部需要更频繁地进行垃圾回收和处理弱引用。因此,只有在确实需要根据对象的生命周期动态调整映射关系时才应该使用 WeakHashMap。在一般情况下,HashMap 或其他 Map 的实现可能更适合。

总结

特性同hashMap