哈喽,各位小伙伴们,你们好呀,我是喵手。
今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。
我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。
小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!
如下是Java集合体系架构图,近期几期内容都是围绕该体系进行知识讲解,以便于同学们学习Java集合篇知识能够系统化而不零散。
前言
在Java开发中,我们经常需要使用Map来存储数据,而Java中提供的Map接口有多个实现类,如HashMap
、TreeMap
、LinkedHashMap
等等。其中,WeakHashMap
是一种特殊的实现类,它提供了一种可以自动回收key所占用的内存的机制。本文将介绍WeakHashMap的详细内容,并分析其应用场景、优缺点以及类代码方法介绍等。
摘要
本文将介绍Java中的WeakHashMap
,包括其定义、特点、源代码解析、应用场景案例、优缺点分析、类代码方法介绍、测试用例以及全文小结。
WeakHashMap
简介
在Java中,WeakHashMap是一种继承自AbstractMap类,实现了Map接口的类。它与HashMap类似,也是一种散列表数据结构,但是它的key是弱引用类型,即如果一个key不再被其他对象所引用,那么这个key所对应的键值对就会被自动移除。因此WeakHashMap可以自动回收不再需要的key所占用的内存,从而避免内存泄漏的问题。
WeakHashMap是线程不安全的,因此通常需要使用Collections.synchronizedMap
方法将其封装成线程安全的Map。
源代码解析
WeakHashMap
的源代码非常复杂,这里只介绍其中的几个核心方法:
put方法
代码语言:java复制public V put(K key, V value) {
Objects.requireNonNull(key, "key == null");
Objects.requireNonNull(value, "value == null");
expungeStaleEntries();
int hash = hash(key.hashCode());
Entry<K,V>[] tab = table;
int index = (tab.length - 1) & hash;
for (Entry<K,V> e = tab[index]; e != null; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
V old = e.value;
e.value = value;
e.recordAccess(this);
return old;
}
}
modCount ;
if (size >= threshold)
resize(tab.length * 2);
createEntry(hash, key, value, index);
return null;
}
put方法用于向WeakHashMap中添加一个键值对。首先,该方法会对key和value进行判空,然后调用expungeStaleEntries方法清除已经过时的键值对。接着,计算出key的哈希值,并根据该哈希值决定将该键值对存储到哪个桶中。如果该桶中已经存在一个与key相同的键值对,那么更新该键值对的value并返回旧的value;否则,将该键值对添加到桶中,并返回null。
expungeStaleEntries方法
代码语言:java复制private void expungeStaleEntries() {
for (Object x; (x = queue.poll()) != null; ) {
synchronized (queue) {
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>) x;
int i = indexFor(e.hash, table.length);
Entry<K,V> prev = table[i];
Entry<K,V> p = prev;
while (p != null) {
Entry<K,V> next = p.next;
if (p == e) {
if (prev == e)
table[i] = next;
else
prev.next = next;
// Must null out stale entries to prevent
// interference with full GCs that occur during
// concurrent execution of the remapping methods.
e.value = null; // Help GC
size--;
break;
}
prev = p;
p = next;
}
}
}
}
expungeStaleEntries方法用于清除已经过时的键值对。如果一个key不再被其他对象所引用,那么这个key所对应的键值对就会被添加到一个队列中。在每次添加新的键值对或者取出键值对时,该方法都会被调用一次,以清除已经过时的键值对。该方法会从队列中取出所有已经过时的键值对,并遍历哈希表中的所有桶,找到并清除所有的过时键值对。
get方法
代码语言:java复制public V get(Object key) {
Object k = maskNull(key);
int h = hash(k);
Entry<K,V>[] tab = getTable();
int index = indexFor(h, tab.length);
Entry<K,V> e = tab[index];
while (e != null) {
if (e.hash == h && eq(k, e.get())) {
V result = e.value;
if (result != null)
e.recordAccess(this);
return result;
}
e = e.next;
}
return null;
}
get方法用于根据key获取value。首先,该方法会将key进行判空,并计算出其哈希值。接着,根据哈希值找到该键值对所在的桶,并遍历该桶中的所有键值对,找到与key相同的键值对,返回其value;若没有找到,则返回null。
应用场景案例
WeakHashMap通常用于需要动态管理大量对象的应用中,可以避免因程序中某些对象不再需要而造成的内存泄漏问题。以下是一些使用WeakHashMap的应用场景:
- 缓存系统:可以使用WeakHashMap作为缓存的实现,这样在缓存中存储的键值对会在key不再被其他对象所引用时自动被移除,避免浪费内存;
- 生命周期管理:对于一些需要动态管理生命周期的对象,如数据库连接、线程池等,可以使用WeakHashMap来保存这些对象,避免因为忘记关闭连接或者资源而造成的内存泄漏问题;
- 监听器管理:在一些应用中,需要使用监听器来处理事件,这些监听器往往会注册到某些对象中去。如果不在需要时将这些监听器移除,就会造成内存泄漏。可以使用WeakHashMap来存储这些对象和其对应的监听器。当这些对象不再被其他对象所引用时,对应的监听器就会被自动移除。
优缺点分析
优点
- 可以避免内存泄漏问题:WeakHashMap使用弱引用保存key,当一个key不再被其他对象所引用时,对应的键值对会被自动移除,从而避免了内存泄漏问题;
- 在动态管理大量对象时具有很好的性能:由于WeakHashMap自动回收已经失效的键值对,因此可以避免内存占用过多的问题,从而提高应用的性能;
- 适用于一些需要动态管理对象的应用:如缓存系统、生命周期管理、监听器管理等。
缺点
- 线程不安全:WeakHashMap是线程不安全的,因此在多线程环境下需要使用
Collections.synchronizedMap
方法将其封装成线程安全的Map; - 由于需要频繁回收已经失效的键值对,因此在性能上会比HashMap略差一些。
类代码方法介绍
以下是WeakHashMap
类的部分方法介绍:
void clear()
:用于清除WeakHashMap中所有的键值对;boolean containsKey(Object key)
:用于判断WeakHashMap是否包含指定的key;- boolean containsValue(Object value):用于判断WeakHashMap是否包含指定的value;
- Set<Entry<K, V>> entrySet():返回WeakHashMap中所有键值对的Set视图;
- boolean equals(Object o):用于判断WeakHashMap是否与给定的对象相等;
- V get(Object key):根据key获取value;
- int hashCode():返回WeakHashMap的哈希码;
- boolean isEmpty():判断WeakHashMap是否为空;
- Set<K> keySet():返回WeakHashMap中所有key的Set视图;
- V put(K key, V value):将指定的key-value键值对放入WeakHashMap中;
- void putAll(Map<? extends K,? extends V> m):将m中所有的键值对放入WeakHashMap中;
- V remove(Object key):根据key移除WeakHashMap中对应的键值对;
- int size():返回WeakHashMap中键值对的数量;
- Collection<V> values():返回WeakHashMap中所有value的Collection视图;
- Object clone():返回WeakHashMap的副本;
- boolean remove(Object key, Object value):移除指定key-value键值对;
- boolean replace(K key, V oldValue, V newValue):替换指定key对应的value;
- V replace(K key, V value):替换指定key对应的value。
测试用例
以下是针对WeakHashMap的简单测试用例:
测试代码演示
代码语言:java复制package com.example.javase.collection;
import java.util.Map;
import java.util.WeakHashMap;
/**
* @author ms
* @date 2023/10/25 16:26
*/
public class WeakHashMapTest {
public static void main(String[] args) {
Map<Number, String> map = new WeakHashMap<>();
Integer key1 = new Integer(1);
Float key2 = new Float(2.0f);
Double key3 = new Double(3.0);
map.put(key1, "value1");
map.put(key2, "value2");
map.put(key3, "value3");
System.out.println("Before GC: " map);
key1 = null;
key2 = null;
key3 = null;
System.gc();
System.out.println("After GC: " map);
}
}
在该测试用例中,我们创建了一个WeakHashMap
,并向其中添加三个键值对。随后,将key1、key2、key3设置为null,并调用System.gc()方法进行垃圾回收。由于三个key均不再被其他对象所引用,因此这三个键值对会被自动移除。最后我们打印出WeakHashMap中剩余的键值对,可以看到只有一个键值对还存在。
测试结果
根据如上测试用例,本地测试结果如下,仅供参考,你们也可以自行修改测试用例或者添加更多的测试数据或测试方法,进行熟练学习以此加深理解。
测试代码分析
根据如上测试用例,在此我给大家进行深入详细的解读一下测试代码,以便于更多的同学能够理解并加深印象。
如上测试用例主要测试了Java中的WeakHashMap
的特性。在代码中,首先创建了一个WeakHashMap
实例,并在其中使用Integer、Float和Double类型的键值对进行了填充。然后输出了填充前的Map内容。接着将Integer、Float和Double类型的键设置为null,以便让它们成为垃圾对象,在执行完这一步操作后,调用Java的垃圾回收器进行垃圾回收,并输出了回收后的Map内容。
WeakHashMap的一个重要特性是,当其键被设置为null或成为垃圾对象后,该键值对将自动从Map中删除。因此,当执行完key1 = null,key2 = null和key3 = null之后,这三个键值对将变成无法访问的垃圾对象,并在下一次垃圾回收器执行时被清除。
因此,当进行垃圾回收后,输出的Map内容将不再包含这三个键值对,也就是只剩下一个空的Map。
全文小结
本文介绍了Java中的WeakHashMap,包括其定义、特点、源代码解析、应用场景案例、优缺点分析、类代码方法介绍以及测试用例等。WeakHashMap是一种可以自动回收key所占用的内存的数据结构,在一些需要动态管理大量对象的应用中具有很好的性能表现。但是由于其线程不安全,需要进行额外的线程安全处理。
总结
本文介绍了Java中的WeakHashMap,它是一种能够自动回收不再需要的key所占用的内存的数据结构。我们通过源代码解析、应用场景案例、优缺点分析、类代码方法介绍以及测试用例等方面详细介绍了WeakHashMap的定义、特点和使用方法。需要注意的是,WeakHashMap是线程不安全的,因此在多线程环境下需要进行额外的线程安全处理。强烈建议在合适的场景使用WeakHashMap来避免内存泄漏问题和提高应用的性能。
... ...
文末
好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。
... ...
学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!
wished for you successed !!!
⭐️若喜欢我,就请关注我叭。
⭐️若对您有用,就请点赞叭。
⭐️若有疑问,就请评论留言告诉我叭。
我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!