网站首页 > 精选教程 正文
Java中的四种引用
什么是引用
在各种编程语言中,都会存在一种“起名”的模式,就是说要为某一个值起个别名,就像每个人有一个名字一样,在Java中有两种类型,一种是基本类型,一种是引用类型。
在Java中我们会使用变量来“起名”,比如基本类型的int i = 0,在内存中会开辟一小块内存存储着变量的值,i是变量的名字,0是变量的值。
还有另外一种类型,也就是引用,除了基本类型,其他都是引用类型,比如Object o = new Object(),对于这种形式的,我们就说o指向了一个对象地址,也可以说o引用了一个对象,程序中通过使用o这个引用来操作其底层真实引用的对象。
在Java中淡化了“指针”,引用其实就是就是一个功能受限但是更加安全的指针。
public static void main(String[] args) {
Object o = new Object();
System.out.println(o); // java.lang.Object@7cca494b
}
可以看到打印的内容是java.lang.Object@7cca494b,后面的数字其实就是内存的地址。
GC回收回调
finalize方法是Object中的方法,当对象被回收的时候,该方法会被调用,用户可以重写该方法,不过一般不建议重写,会引发性能、死锁等一系列问题,我们学习的时候可以重写。
finalize是JDK9以前的推荐方法,在JDK9以及以后的版本中,该方法已经被弃用,推荐使用java.lang.ref.Cleaner,使用方法比较简单,看后面的示例即可。
强引用
在Java中,我们见到的最常见的引用就是强应用,当一个对象被分配给一个变量时,该变量就包含了对该对象的强引用。只要存在对该对象的强引用,垃圾收集器就不会回收该对象。
package cn.programtalk;
import java.lang.ref.Cleaner;
public class RefSample{
static Cleaner cleaner = Cleaner.create();
public static void main(String[] args) {
RefSample rs = new RefSample();
cleaner.register(rs, () -> {
System.out.println("rs引用的对象被gc回收");
});
// rs = null;
System.gc();
System.out.println(rs); // cn.programtalk.RefSample@7699a589
}
}
可以看到虽然执行System.gc()(执行gc),但是rs依然持有 new RefSample()的引用,也正验证了强应用的特点,取消注释再次执行,rs值打印为null,并且控制台输出”rs引用的对象被GC回收“,说明对象被GC回收了。
软引用
软引用是一种相对弱化的引用类型。当系统内存不足时,垃圾收集器会回收仅被软引用指向的对象。可以使用java.lang.ref.SoftReference类来创建软引用。
通过代码来演示下:
package cn.programtalk;
import java.lang.ref.Cleaner;
import java.lang.ref.SoftReference;
public class RefSample {
static Cleaner cleaner = Cleaner.create();
public static void main(String[] args) {
SoftReference<byte[]> ref = new SoftReference<>(new byte[1024 * 1024 * 5]);
cleaner.register(ref.get(), () -> {
System.out.println("ref弱引用的对象被gc回收");
});
System.out.println(ref.get()); // ①
System.gc();
System.out.println(ref.get()); // ②
byte[] bytes = new byte[1024 * 1024 * 5];
System.out.println(ref.get()); // ③
}
}
为了方便验证,我设置最大内存为10M(-Xmx10m)。
看下运行结果:
在①出打印出了对象信息,说明此时对象存在,在②处也打印出来了对象信息,说明对象依然没有被回收,在②之前使用了System.gc()为什么依然没有回收呢?这是因为,首先最大内存是10M,而软引用中的对象是5M,此时内存够用,所以没有回收。
接下来在③处打印了对象的是是null(在②之后我也并没有gc代码),说明对象被回收了,打印了"引用的对象被gc回收"也验证了对象确实被回收了,为什么此时就被回收了呢,这是因为程序又要创建byte[] bytes = new byte[1024 * 1024 * 5];5M的对象,内存最大是10M,此时内存使用过高,明显不足了,所以回收了弱引用的对象。
如果bytes的内存再大些,就会直接抛出堆内存不足的异常了,比如我修改bytes为10M,重新运行,结果如下:
软引用通常用来实现内存敏感的缓存。如果还有空闲内存,就可以暂时保留缓存,当内存不足时清理掉,这样就保证了使用缓存的同时,不会耗尽内存。
弱引用
弱引用比软引用更弱。当垃圾收集器运行时,无论当前内存是否充足,都会回收仅被弱引用指向的对象。可以使用java.lang.ref.WeakReference类来创建弱引用。
package cn.programtalk;
import java.lang.ref.Cleaner;
import java.lang.ref.WeakReference;
public class RefSample {
static Cleaner cleaner = Cleaner.create();
public static void main(String[] args) {
WeakReference<RefSample> ref = new WeakReference<>(new RefSample());
cleaner.register(ref.get(), () -> {
System.out.println("引用的对象被gc回收");
});
System.gc();
System.out.println(ref.get());
}
}
运行结果如下:
可以看到发生gc就会将弱引用对象回收。
JDK中的ThreadLocal就使用了弱引用。
虚引用
PhantomReference(虚引用)是Java中最弱的一种引用类型。与其他几种引用类型不同,它不能单独使用,必须和引用队列(ReferenceQueue)联合使用。虚引用主要用于跟踪对象被垃圾收集器回收的活动,使用java.lang.ref.PhantomReference来创建虚引用。之前使用到的Cleaner就是通过虚引用实现的。
package cn.programtalk;
import java.lang.ref.*;
public class RefSample {
public static void main(String[] args) throws InterruptedException {
RefSample rs = new RefSample();
ReferenceQueue<RefSample> refQueue = new ReferenceQueue<>();
PhantomReference<RefSample> phantomRef = new PhantomReference<>(rs, refQueue);
System.out.println(rs);
rs = null;
System.out.println("垃圾回收之前: " + phantomRef.get());
System.gc();
Thread.sleep(1000);
System.out.println("垃圾回收之后: " + phantomRef.get());
Reference<? extends RefSample> ref = refQueue.remove();
if (ref != null) {
System.out.println("对象被回收." + ref.get());
}
}
}
打印结果如下:
垃圾回收前后,都无法获取对象,这是没错的,虚引用就是无法获取到具体的对象。
因为打印了”对象被回收。null“字样,说明确实将被回收的对象放入到了队列中。
猜你喜欢
- 2024-11-14 Java强引用、软引用、弱引用和虚引用使用场景
- 2024-11-14 Java中的四种引用类型的区别与联系?
- 2024-11-14 Python 中弱引用的神奇用法与原理探析
- 2024-11-14 Java的4中引用类型:强引用,软引用,弱引用,虚引用
- 2024-11-14 JVM中如何理解强引用、软引用、弱引用、虚引用?
- 2024-11-14 吃透源码的每一个细节和设计原理--ThreadLocal
- 2024-11-14 Java,基本类型和引用类型,强引用、软引用、弱引用、虚引用
- 2024-11-14 一文带你理解jvm之强软弱虚引用 强软弱虚 程序中应用
- 2024-11-14 面试被问java如何实现强引用、软引用、弱引用、虚引用你知道么?
- 2024-11-14 「教3妹学java」11.强引用,弱引用,软引用和虚引用的区别是什么
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)