Java、Android引用类型

Java/Android中有四种引用类型,分别是:
Strong reference - 强引用
Soft Reference - 软引用
Weak Reference - 弱引用
Phantom Reference - 虚引用

不同的引用类型有着不同的特性,同时也对应着不同的使用场景。

Strong reference - 强引用

实际编码中最常见的一种引用类型。常见形式如:A a = new A();等。强引用本身存储在栈内存中,其存储指向对内存中对象的地址。一般情况下,当对内存中的对象不再有任何强引用指向它时,垃圾回收机器开始考虑可能要对此内存进行的垃圾回收。如当进行编码:a = null,此时,刚刚在堆中分配地址并新建的a对象没有其他的任何引用,当系统进行垃圾回收时,堆内存将被垃圾回收。

SoftReference、WeakReference、PhantomReference都是类java.lang.ref.Reference的子类。Reference作为抽象基类,定义了其子类对象的基本操作。Reference子类都具有如下特点:

  • Reference子类不能无参化直接创建,必须至少以强引用对象为构造参数,创建各自的子类对象;
  • 因为1中以强引用对象为构造参数创建对象,因此,使得原本强引用所指向的堆内存中的对象将不再只与强引用本身直接关联,与Reference的子类对象的引用也有一定联系。且此种联系将可能影响到对象的垃圾回收。

根据不同的子类对象对其指示对象(强引用所指向的堆内存中的对象)的垃圾回收不同的影响特点,分别形成了三个子类,即SoftReference、WeakReference和PhantomReference

Soft Reference - 软引用

软引用的一般使用形式如下:
A a = new A();
SoftReference srA = new SoftReference(a);
通过对象的强引用为参数,创建了一个SoftReference对象,并使栈内存中的wrA指向此对象。
此时,进行如下编码:a = null,对于原本a所指向的A对象的垃圾回收有什么影响呢?
先直接看一下下面一段程序的输出结果:

public class ReferenceTest {public static void main(String[] args) {A a = new A();SoftReference<A> srA = new SoftReference<A>(a);a = null;if (srA.get() == null) {System.out.println("a对象进入垃圾回收流程");} else {System.out.println("a对象尚未被回收" + srA.get());}// 垃圾回收System.gc();if (srA.get() == null) {System.out.println("a对象进入垃圾回收流程");} else {System.out.println("a对象尚未被回收" + srA.get());}}
}class A {}
输出结果为:
a对象尚未被回收A@4807ccf6
a对象尚未被回收A@4807ccf6

当 a = null后,堆内存中的A对象将不再有任何的强引用指向它,但此时尚存在srA引用的对象指向A对象。当第一次调用srA.get()方法返回此指示对象时,由于垃圾回收器很有可能尚未进行垃圾回收,此时get()是有结果的,这个很好理解。当程序执行System.gc();强制垃圾回收后,通过srA.get(),发现依然可以得到所指示的A对象,说明A对象并未被垃圾回收。那么,软引用所指示的对象什么时候才开始被垃圾回收呢?需要满足如下两个条件:
1.当其指示的对象没有任何强引用对象指向它;
2.当虚拟机内存不足时。
因此,SoftReference变相的延长了其指示对象占据堆内存的时间,直到虚拟机内存不足时垃圾回收器才回收此堆内存空间。

Weak Reference - 弱引用

同样的,软引用的一般使用形式如下:
A a = new A();
WeakReference wrA = new WeakReference(a);
当没有任何强引用指向此对象时, 其垃圾回收又具有什么特性呢?

public class ReferenceTest {public static void main(String[] args) {A a = new A();WeakReference<A> wrA = new WeakReference<A>(a);a = null;if (wrA.get() == null) {System.out.println("a对象进入垃圾回收流程");} else {System.out.println("a对象尚未被回收" + wrA.get());}// 垃圾回收System.gc();if (wrA.get() == null) {System.out.println("a对象进入垃圾回收流程");} else {System.out.println("a对象尚未被回收" + wrA.get());}}
}class A {}
输出结果为:
a对象尚未被回收A@52e5376a
a对象进入垃圾回收流程

输出的第一条结果解释同上。当进行垃圾回收后,wrA.get()将返回null,表明其指示对象进入到了垃圾回收过程中。因此,对弱引用特点总结为:
WeakReference不改变原有强引用对象的垃圾回收时机,一旦其指示对象没有任何强引用对象时,此对象即进入正常的垃圾回收流程。
那么,依据此特点,很可能有疑问:WeakReference存在又有什么意义呢?
其主要使用场景见于:当前已有强引用指向强引用对象,此时由于业务需要,需要增加对此对象的引用,同时又不希望改变此引用的垃圾回收时机,此时WeakReference正好符合需求,常见于一些与生命周期的场景中。

ReferenceQueue

对于SoftReference和WeakReference,还有一个构造器参数为ReferenceQueue,当SoftReference或WeakReference所指示的对象确实被垃圾回收后,其引用将被放置于ReferenceQueue中。注意上文中,当SoftReference或WeakReference的get()方法返回null时,仅是表明其指示的对象已经进入垃圾回收流程,此时对象不一定已经被垃圾回收。而只有确认被垃圾回收后,其引用才会被放置于ReferenceQueue中。

public static void main(String[] args) {A a = new A();ReferenceQueue referenceQueue = new ReferenceQueue();WeakReference<Object> weakReference = new WeakReference<Object>(a, referenceQueue);a = null;if(weakReference.get() == null){System.out.println("a对象进入垃圾回收流程");}else {System.out.println("a对象尚未被回收" + weakReference.get());}System.out.println("rq item:" + referenceQueue.poll());System.gc();if(weakReference.get() == null){System.out.println("a对象进入垃圾回收流程");}else {System.out.println("a对象尚未被回收" + weakReference.get());}System.out.println("rq item:" + referenceQueue.poll());}public static class A{@Overrideprotected void finalize() throws Throwable {System.out.println("A finalize");super.finalize();}}
输出结果为:
a对象尚未被回收@4554617c
rq item:null
a对象进入垃圾回收流程
rq item:null
A finalize

当调用System.gc()后,输出‘a对象进入垃圾回收流程’说明a已经开始进入了垃圾回收流程,但是还未被真正回收,因为Java对象被回收时会调用期finalize方法;此时我们立刻调用referenceQueue.poll()得到的是空,这样验证了对象只有gc已回收后WeakReference或SoftReference才会被加入ReferenceQueue。

现在我们再gc后,进行一段时间的延时后再调用referenceQueue.poll():
 public static void main(String[] args) {A a = new A();ReferenceQueue referenceQueue = new ReferenceQueue();WeakReference<Object> weakReference = new WeakReference<Object>(a, referenceQueue);a = null;if(weakReference.get() == null){System.out.println("a对象进入垃圾回收流程");}else {System.out.println("a对象尚未被回收" + weakReference.get());}System.out.println("rq item:" + referenceQueue.poll());System.gc();if(weakReference.get() == null){System.out.println("a对象进入垃圾回收流程");}else {System.out.println("a对象尚未被回收" + weakReference.get());}try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("rq item:" + referenceQueue.poll());}public static class A{@Overrideprotected void finalize() throws Throwable {System.out.println("A finalize");super.finalize();}}
输出结果
a对象尚未被回收@4554617c
rq item:null
a对象进入垃圾回收流程
A finalize
rq item:@74a14482

此时referenceQueue中存在了WeakReference,实验的结果也就不言而喻了。

PhantomReference虚引用

与SoftReference或WeakReference相比,PhantomReference主要差别体现在如下几点:

  • PhantomReference只有一个构造函数PhantomReference(T referent, ReferenceQueue<? super T> q),因此,PhantomReference使用必须结合ReferenceQueue;
  • 不管有无强引用指向PhantomReference的指示对象,PhantomReference的get()方法返回结果都是null。
public class ReferenceTest {public static void main(String[] args) {A a = new A();ReferenceQueue<A> rq = new ReferenceQueue<A>();PhantomReference<A> prA = new PhantomReference<A>(a, rq);System.out.println("prA.get():" + prA.get());a = null;System.gc();try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("rq item:" + rq.poll());}
}class A {}
输出结果为:
prA.get():null
rq item:java.lang.ref.PhantomReference@1da12fc0

代码中的Thread.sleep(1);作用与上例中相同,都是确保垃圾回收线程能够执行。否则,进进入垃圾回收流程而没有真正被垃圾回收的指示对象的虚引用是不会被加入到PhantomReference中的。

与WeakReference相同,PhantomReference并不会改变其指示对象的垃圾回收时机。ReferenceQueue的作用主要是用于监听Java对象是否已经被垃圾回收。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/60604.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络安全,文明上网(2)加强网络安全意识

前言 在当今这个数据驱动的时代&#xff0c;对网络安全保持高度警觉已经成为每个人的基本要求。 网络安全意识&#xff1a;信息时代的必备防御 网络已经成为我们生活中不可或缺的一部分&#xff0c;信息技术的快速进步使得我们对网络的依赖性日益增强。然而&#xff0c;网络安全…

微前端基础知识入门篇(二)

概述 在上一篇介绍了一些微前端的基础知识,详见微前端基础知识入门篇(一)。本文主要介绍qiankun微前端框架的实战入门内容。 qiankun微前端实践 通过Vite脚手架分别创建三个程序,主应用A为:vite+vue3+ts,两个微应用分别为B:vite+vue3+ts;C:vite+React+ts。因为qiankun的…

实时数据研发 | Flink技术栈

下周要开始接触一些实时的内容了&#xff0c;想来是很幸运的&#xff0c;这是我在新人培训上提问过技术前辈的问题&#xff1a;“想学习实时相关技术&#xff0c;但是部门没有类似的需求&#xff0c;应该如何提升&#xff1f;”当时师姐说先用心去学&#xff0c;然后向主管证明…

DataGear 企业版 1.3.0 发布,数据可视化分析平台

DataGear 企业版 1.3.0 已发布&#xff0c;欢迎体验&#xff01; http://datagear.tech/pro/ 企业版 1.3.0 新增看板全局导入库管理功能、统一登录功能改进、安全增强&#xff0c;具体更新内容如下&#xff1a; 新增&#xff1a;新增看板全局导入库管理功能&#xff0c;支持…

Spark SQL 之 QueryStage

ExchangeQueryStageExec ExchangeQueryStageExec 分为两种

el-table根据指定字段合并行和列+根据屏幕高度实时设置el-table的高度

文章目录 html代码script代码arraySpanMethod.js代码 html代码 <template><div class"rightBar"><cl-table ref"tableData"border :span-method"arraySpanMethod" :data"tableData" :columns"columns":max-…

探索 RocketMQ:企业级消息中间件的选择与应用

一、关于RocketMQ RocketMQ 是一个高性能、高可靠、可扩展的分布式消息中间件&#xff0c;它是由阿里巴巴开发并贡献给 Apache 软件基金会的一个开源项目。RocketMQ 主要用于处理大规模、高吞吐量、低延迟的消息传递&#xff0c;它是一个轻量级的、功能强大的消息队列系统&…

设计模式之 责任链模式

责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为型设计模式&#xff0c;旨在将多个处理对象通过链式结构连接起来&#xff0c;形成一条处理请求的链条。每个处理对象都有机会处理请求&#xff0c;或者将请求传递给链中的下一个对象。这样&#x…

Flink-Source的使用

Data Sources 是什么呢&#xff1f;就字面意思其实就可以知道&#xff1a;数据来源。 Flink 做为一款流式计算框架&#xff0c;它可用来做批处理&#xff0c;也可以用来做流处理&#xff0c;这个 Data Sources 就是数据的来源地。 flink在批/流处理中常见的source主要有两大类…

python开发之Linux

文章目录 1. 基础2. 进阶链接压缩/解压缩 文件权限用户远程操作编辑文件软件安装 1. 基础 # 查看当前目录下文件 ls# 查看当前目录 pwd# 清除界面内容 clear# 切换目录 cd# 创建目录 mkdir# 创建文件 touch 文件 vi 文件# 强制删除 rm -rf # 复制文件 cp 复制文件 复制文件路径…

OceanBase 驱动类获取数据库精确类型 “Oracle|MySQL”

当我们需要获取 DataSource 对象所连接的数据库的数据库名称时&#xff0c;正常是通过如下代码来获取&#xff1a; String databaseName dataSource.getConnection().getMetaData().getDatabaseProductName();我们知道 OceanBase 数据库企业版的租户是区分 Oracle 和 MySQL 两…

element-plus入门教程:Button

一、Button组件概述 Element Plus的Button组件是一个常用的操作按钮&#xff0c;提供了多种类型、尺寸、状态等配置选项&#xff0c;以满足不同的交互需求。 二、安装Element Plus 在Vue 3项目中&#xff0c;可以通过npm或yarn来安装Element Plus。 npm install element-pl…

深入解析 Cron 表达式高级用法:Spring 与 Linux Crontab 的全面对比与实践20241120

深入解析 Cron 表达式高级用法&#xff1a;Spring 与 Linux Crontab 的全面对比与实践 任务调度是后台服务中的重要组成部分&#xff0c;无论是定期数据备份、日志归档还是周期性报表生成&#xff0c;Cron 表达式始终是描述这些任务规则的核心工具。本文将聚焦 Spring Cron 表…

python中的map、split、join函数的作用 => ACM输入输出流

map(func,iter) lst_str ["1", "2", "3"] # 得到lst_num为[1, 2, 3] lst_num list(map(int, lst_str))如果想把一个列表里的所有元素批量地调用某一个函数&#xff0c;并映射得到一个新的列表&#xff08;原列表中元素相对位置不变&#xff0…

【数据结构】七种常用排序总结

一、七种排序及其讲解 以下为七种排序的讲解&#xff1a; 【数据结构】插入排序——直接插入排序 和 希尔排序 【数据结构】选择排序——选择排序 和 堆排序 【数据结构】交换排序——冒泡排序 和 快速排序 【数据结构】归并排序 —— 递归及非递归解决归并排序 二、排序的…

【AI日记】24.11.23 学习谷歌数据分析初级课程-第4课

【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI日记】 核心工作 内容&#xff1a;学习谷歌数据分析初级课程地址&#xff1a;第四课《从脏数据到干净数据的处理》时间&#xff1a;4 小时评估&#xff1a;不错&#xff0c;完成 读书 书名&#xff1a;權力與進步时…

计算机网络(14)ip地址超详解

先看图&#xff1a; 注意看第三列蓝色标注的点不会改变&#xff0c;A类地址第一个比特只会是0&#xff0c;B类是10&#xff0c;C类是110&#xff0c;D类是1110&#xff0c;E类是1111. IPv4地址根据其用途和网络规模的不同&#xff0c;分为五个主要类别&#xff08;A、B、C、D、…

HashMap底层原理

jdk1.8之后hashmap底层结构 jdk1.8之后&#xff0c;是哈希表数据结构&#xff0c;也可以说是数组链表或红黑树&#xff0c;下图是没有添加数据的一个hashmap。 现在开始添加数据&#xff0c;看下面具体步骤 put操作 如下&#xff0c;我们来简单看看hashmap的put源码&#xff…

【GD32】(三) ISP基本使用

0 前言 有一块GD32的板子不知道为啥用着用着就下载不了程序了&#xff0c;没办法&#xff0c;只能另寻他法。作为STM32的平替&#xff0c;GD32的功能和STM32基本是一致的&#xff0c;所以也可以使用ISP来下载程序。于是就开始复活这块板子。 1 BOOT模式 对于熟悉STM32开发的人…

《下载别人的python项目,如何安装 requirements.txt 中的包》

在开发过程中&#xff0c;我们经常会下载别人的开源项目进行学习或二次开发。然而&#xff0c;下载项目后&#xff0c;如何正确安装项目所需的依赖包是一个常见的问题。本文将详细介绍如何使用 requirements.txt 文件来安装项目依赖包&#xff0c;并确保项目在本地环境中正常运…