Java集合—WeakHashMap

Java集合—WeakHashMap

WeakHashMap的使用
WeakHashMap的使用和HashMap类似,区别是WeakHashMap除了自身有对key的引用,没有其他引用,也就是弱引用,所以WeakHashMap中的key可能就会被GC(垃圾回收器)回收,value值也会被回收
WeakHashMap的特点
允许key和value值为null(和HashMap一样)
WeakHashMap也是哈希表,但它的key为弱键
底层数据结构为数组+链表
WeakHashMap底层源码实现

  • 类的继承关系
public class WeakHashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V> {

WeakHashMap和HashMap一样,继承自AbstractMap,实现Map接口

  • 类的成员变量
//Entry[]数组类型,存储哈希表的键值对
Entry<K,V>[] table;
//已保存的键值对的数量
private int size;
//用来判断是否进行扩容(threshold>=size时进行扩容)
private int threshold;
//加载因子
private final float loadFactor;
//保存已被GC回收的key
private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
//用来实现fast-fail机制
int modCount;
  • 类的构造函数

1.默认构造函数

public WeakHashMap() {
        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
    }

2.自定义容量大小的构造函数

public WeakHashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

3.自定义容量大小和加载因子的构造函数

 public WeakHashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Initial Capacity: "+
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;

        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal Load factor: "+
                                               loadFactor);
        int capacity = 1;
        while (capacity < initialCapacity)
            capacity <<= 1;
        table = newTable(capacity);
        this.loadFactor = loadFactor;
        threshold = (int)(capacity * loadFactor);
    }

4.包含子Map的构造函数

public WeakHashMap(Map<? extends K, ? extends V> m) {
        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
                DEFAULT_INITIAL_CAPACITY),
             DEFAULT_LOAD_FACTOR);
        putAll(m);
    }
  • 主要方法分析

1.put(K key, V value)方法

 public V put(K key, V value) {
         // 确定key值,允许key为null
         Object k = maskNull(key);
         // 获取器hash值
         int h = hash(k);
         // 获取tab
         Entry<K,V>[] tab = getTable();
         // 确定在tab中的位置 简单的&操作
         int i = indexFor(h, tab.length);
         // 遍历,是否要进行覆盖操作  
         for (Entry<K,V> e = tab[i]; e != null; e = e.next) {
             if (h == e.hash && eq(k, e.get())) {
                 V oldValue = e.value;
                 if (value != oldValue)
                     e.value = value;
                 return oldValue;
             }
         }
         
         // 修改次数自增
         modCount++;
         // 取出i上的元素
         Entry<K,V> e = tab[i];
         // 构建链表,新元素在链表头
         tab[i] = new Entry<>(k, value, queue, h, e);
         // 检查是否需要扩容
         if (++size >= threshold)
             resize(tab.length * 2);
         return null;   

WeakHashMap的put操作与HashMap相似,都会进行覆盖操作,但是注意插入新节点是从链表头插入
2.get(Object key) 方法

 public V get(Object key) {
         // 确定key
         Object k = maskNull(key);
         // 计算其hashCode
         int h = hash(k);
         Entry<K,V>[] tab = getTable();
         int index = indexFor(h, tab.length);
         // 获取对应位置上的元素
         Entry<K,V> e = tab[index];
         while (e != null) {
             // 如果hashCode相同,并且key也相同,则返回,否则继续循环
             if (e.hash == h && eq(k, e.get()))
                 return e.value;
             e = e.next;
         }
         // 未找到,则返回null
         return null;
     }

根据key找到对应元素,找到的返回该元素,找不到返回null
3.remove(Object key)方法

 public V remove(Object key) {
         Object k = maskNull(key);
         int h = hash(k);
         Entry<K,V>[] tab = getTable();
         int i = indexFor(h, tab.length);
         // 数组上第一个元素
         Entry<K,V> prev = tab[i];
         Entry<K,V> e = prev;
         // 循环 
         while (e != null) {
             Entry<K,V> next = e.next;
             // 如果hash值相同,并且key一样,则进行移除操作
             if (h == e.hash && eq(k, e.get())) {
                 // 修改次数自增
                 modCount++;
                 // 元素个数自减
                 size--;
                 // 如果就是头元素,则直接移除即可
                 if (prev == e)
                     tab[i] = next;
                 else
                     // 否则将前驱元素的next赋值为next,则将e移除
                     prev.next = next;
                 return e.value;
             }
             // 更新prev和e,继续循环
             prev = e;
             e = next;
         }
         return null;
     }

在删除元素时,注意元素是链表头时直接移除元素即可
4.resize(int newCapacity)方法

 WeakHashMap的扩容方法
void resize(int newCapacity) {
        //原数组长度
        Entry<K,V>[] oldTable = getTable();
        int oldCapacity = oldTable.length;
        if (oldCapacity == MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return;
        }
        //新数组
        Entry<K,V>[] newTable = newTable(newCapacity);
        transfer(oldTable, newTable);
        table = newTable;
        //扩容
        if (size >= threshold / 2) {
            threshold = (int)(newCapacity * loadFactor);
        } else {
            //清除被GC回收的value
            expungeStaleEntries();
            transfer(newTable, oldTable);
            table = oldTable;
        }
    }

WeakHashMap的扩容要注意key可能会被GC回收的情况

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值