10分钟带你理解Java中的弱引用
作者:daisy 发布时间:2023-02-09 10:35:55
前言
本文尝试从What、Why、How这三个角度来探索Java中的弱引用,帮助大家理解Java中弱引用的定义、基本使用场景和使用方法。
一、 What——什么是弱引用?
Java中的弱引用具体指的是java.lang.ref.WeakReference<T>
类,我们首先来看一下官方文档对它做的说明:
弱引用对象的存在不会阻止它所指向的对象被垃圾回收器回收。弱引用最常见的用途是实现规范映射(canonicalizing mappings,比如哈希表)。
假设垃圾收集器在某个时间点决定一个对象是弱可达的(weakly reachable)(也就是说当前指向它的全都是弱引用),这时垃圾收集器会清除所有指向该对象的弱引用,然后把这个弱可达对象标记为可终结(finalizable)的,这样它随后就会被回收。与此同时或稍后,垃圾收集器会把那些刚清除的弱引用放入创建弱引用对象时所指定的引用队列(Reference Queue)中。
实际上,Java中存在四种引用,它们由强到弱依次是:强引用、软引用、弱引用、虚引用。
下面我们简单介绍下除弱引用外的其他三种引用:
1、强引用(Strong Reference):通常我们通过new来创建一个新对象时返回的引用就是一个强引用,若一个对象通过一系列强引用可到达,它就是强可达的(strongly reachable),那么它就不被回收
2、软引用(Soft Reference):软引用和弱引用的区别在于,若一个对象是弱引用可达,无论当前内存是否充足它都会被回收,而软引用可达的对象在内存不充足时才会被回收,因此软引用要比弱引用“强”一些
3、虚引用(Phantom Reference):虚引用是Java中最弱的引用,那么它弱到什么程度呢?它是如此脆弱以至于我们通过虚引用甚至无法获取到被引用的对象,虚引用存在的唯一作用就是当它指向的对象被回收后,虚引用本身会被加入到引用队列中,用作记录它指向的对象已被回收。
二、Why——为什么使用弱引用?
考虑下面的场景:现在有一个Product
类代表一种产品,这个类被设计为不可扩展的,而此时我们想要为每个产品增加一个编号。一种解决方案是使用HashMap<Product, Integer>
。于是问题来了,如果我们已经不再需要一个Product
对象存在于内存中(比如已经卖出了这件产品),假设指向它的引用为productA
,我们这时会给productA
赋值为null
,然而这时productA
过去指向的Product
对象并不会被回收,因为它显然还被HashMap
引用着。所以这种情况下,我们想要真正的回收一个Product
对象,仅仅把它的强引用赋值为null
是不够的,还要把相应的条目从HashMap
中移除。显然“从HashMap
中移除不再需要的条目”这个工作我们不想自己完成,我们希望告诉垃圾收集器:在只有HashMap
中的key
在引用着Product
对象的情况下,就可以回收相应Product
对象了。显然,根据前面弱引用的定义,使用弱引用能帮助我们达成这个目的。我们只需要用一个指向Product
对象的弱引用对象来作为HashMap
中的key
就可以了。
三、How——如何使用弱引用?
拿上面介绍的场景举例,我们使用一个指向Product
对象的弱引用对象来作为HashMap
的key
,只需这样定义这个弱引用对象:
Product productA = new Product(...);
WeakReference<Product> weakProductA = new WeakReference<>(productA);
现在,若引用对象weakProductA
就指向了Product
对象productA
。那么我们怎么通过weakProduct
获取它所指向的Product
对象productA
呢?
很简单,只需要下面这句代码:
Product product = weakProductA.get();
实际上,对于这种情况,Java类库为我们提供了WeakHashMap
类,使用和这个类,它的键自然就是弱引用对象,无需我们再手动包装原始对象。这样一来,当productA
变为null
时(表明它所引用的Product
已经无需存在于内存中),这时指向这个Product
对象的就是由弱引用对象weakProductA
了,那么显然这时候相应的Product
对象时弱可达的,所以指向它的弱引用会被清除,这个Product
对象随即会被回收,指向它的弱引用对象会进入引用队列中。
四、引用队列
下面我们来简单地介绍下引用队列的概念。实际上,WeakReference
类有两个构造函数:
//创建一个指向给定对象的弱引用
WeakReference(T referent)
//创建一个指向给定对象并且登记到给定引用队列的弱引用
WeakReference(T referent, ReferenceQueue<? super T> q)
我们可以看到第二个构造方法中提供了一个ReferenceQueue
类型的参数,通过提供这个参数,我们便把创建的弱引用对象注册到了一个引用队列上,这样当它被垃圾回收器清除时,就会把它送入这个引用队列中,我们便可以对这些被清除的弱引用对象进行统一管理。
五、总结
好了,这篇文章的内容到这就结束了,由于个人水平有限,叙述中难免存在不准确或是不清晰的地方,希望大家可以指出,谢谢大家对脚本之家的支持。
猜你喜欢
- 概述最近项目上反馈某个重要的定时任务突然不执行了,很头疼,开发环境和测试环境都没有出现过这个问题。定时任务采用的是ScheduledThre
- 什么事读写分离读写分离,基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELEC
- 表关联上一篇介绍了JPA的简单使用,这一篇介绍JPA在表关联上的使用一对一配置参数JPA对于数据实体一对一映射使用的是@OneToOne注解
- 谈到 Java 的线程池最熟悉的莫过于 ExecutorService 接口了,jdk1.5 新增的 java.util.concurren
- Java RandomAccessFile 指定位置实现文件读取与写入RandomAccessFile是属于随机读取类,是可以对文件本身的内
- List集合相信大家在开发过程中几乎都会用到。有时候难免会遇到集合里的数据是重复的,需要进行去除。然而,去重方式有好几种方式,你用的是哪种方
- Integer获取第一位和最后一位并截取场景获取 5,10,15,25,30; 判断尾数为5的进入判断public static void
- 利用Android的ApiDemos的Rotate3dAnimation实现了个图片3D旋转的动画,围绕Y轴进行旋转,还可以实现Z轴的缩放。
- JavaBean根据指定条件设置属性值默认值使用场景当bean数据中已经装配好其他数据,在逻辑以及数据转换完成的最后一步进行数据默认值设置;
- 最近接触到个新项目,发现它用了一个比较有意思的框架,可以说实现了我刚入行时候的梦想,所以这里马不停蹄的和大家分享下。在我刚开始工作接触的项目
- 二分法查找,顾名思义就是要将数据每次都分成两份然后再去找到你想要的数据,我们可以这样去想,二分法查找很类似与我们平时玩的猜价格游戏,当你报出
- 本文实例讲述了Java使用备忘录模式实现过关类游戏功能。分享给大家供大家参考,具体如下:一.模式定义备忘录模式,在不破坏封闭的前提下,捕获一
- like模糊查询特殊字符报错转义处理方案1 <if test="projectName!
- Java泛型是JDK 5引入的一个特性,它允许我们定义类和接口的时候使用参数类型,泛型在集合框架中被广泛使用。类型擦除是泛型中最让人困惑的部
- java中如何表示圆周率设计一个Shape接口和它的两个实现类Square和Circle。 要求如下(1) Shape接口中有一个抽象方法a
- 前言我们在日常开发中,经常会用到一个系统需要链接多个数据库来实现业务的需求,比如多个系统之间数据调用、两个数据之间同步等等。今天给大家分享使
- 一般,我们的web应用都是只有在用户登录之后才允许操作的,也就是说我们不允许非登录认证的用户直接访问某些页面或功能菜单项。我还记得很久以前我
- Java Double相加出现的怪事问题的提出编译运行下面这个程序会看到什么public class test { public stati
- 引言mysql 和 oracle 插入的时候有一个很大的区别是:oracle 支持序列做 id;mysql 本身有一个列可以做自增长字段。m
- 1、dose not point to a valid jvm installation出错问题按照以下方法设置一定可以不会出现这个错误。我