【JAVA基础面经】Java中的引用类型
文章目录
- Java中的引用类型
- 一、强引用(Strong Reference)
- 二、软引用(Soft Reference)
- 三、弱引用(Weak Reference)
- 四、虚引用(Phantom Reference)
Java中的引用类型
在 Java 中,当我们写下 Object obj = new Object(); 时,obj 是一个引用,new Object() 才是对象本体。可以把引用想象成一根绳子,对象就是绳子另一端拴着的气球。只要有绳子拉着,气球就不会飞走(不会被 GC 回收)。
Java 提供了四种不同强度的引用类型,由强到弱依次为:强引用、软引用、弱引用、虚引用。合理使用它们可以更好地管理内存,实现缓存、防止内存泄漏等场景。
一、强引用(Strong Reference)
强引用是 Java 中最常见的引用类型,也就是我们平时直接 new 出来的对象赋值。
Objectobj=newObject();// obj 是强引用只要强引用还存在,垃圾收集器就永远不会回收掉被引用的对象。即使内存快要爆了,JVM 抛出 OutOfMemoryError 也不会去动它
Objectobj=newObject();// 强引用,气球被拉着// 即使内存紧张,这个对象也绝对安全obj=null;// 主动把绳子剪断// 现在这个对象没有强引用了,GC 可以回收二、软引用(Soft Reference)
软引用通过 java.lang.ref.SoftReference 类实现,它比强引用弱一级。
SoftReference<MyObject>softRef=newSoftReference<>(newMyObject());软引用就像一根弹性皮筋。当 JVM 内存充足时,垃圾收集器不会回收软引用指向的对象;但当内存不足、即将抛出 OutOfMemoryError 时,JVM 会先回收软引用指向的对象,把内存腾出来。
ObjectstrongObj=newObject();SoftReference<Object>softRef=newSoftReference<>(strongObj);strongObj=null;// 切断强引用,只剩软引用System.out.println("GC前:"+softRef.get());// 大概率能获取到System.gc();// 内存充足时,GC 不会回收软引用对象System.out.println("GC后(内存充足):"+softRef.get());// 通常还在// 如果不断分配内存直到 OOM,JVM 会清理软引用- 使用场景:
- 内存敏感的缓存:比如图片缓存、网页缓存。内存充足时直接从缓存拿,内存紧张时自动释放,不会导致 OOM。
- 需要可丢弃的中间数据:比如地图应用中的瓦片数据,重建成本较高但可丢弃。
三、弱引用(Weak Reference)
弱引用是通过 java.lang.ref.WeakReference 类来创建的
WeakReference<MyObject>weakRef=newWeakReference<>(newMyObject());弱引用就像一根头发丝。虽然也能牵着气球,但力量非常微弱。当 JVM 进行垃圾回收时,无论当前内存是否充足,都会立刻回收掉只有弱引用指向的对象。
publicclassWeakReferenceDemo{publicstaticvoidmain(String[]args){// 创建一个强引用ObjectstrongObj=newObject();// 创建一个弱引用指向这个对象WeakReference<Object>weakRef=newWeakReference<>(strongObj);System.out.println("GC前,弱引用获取:"+weakRef.get());// 能拿到对象strongObj=null;// 切断强引用,现在只剩弱引用了System.gc();// 建议JVM进行垃圾回收System.out.println("GC后,弱引用获取:"+weakRef.get());// 大概率输出 null}}- 适用场景
- 缓存系统:适合
实现自动清理的缓存。普通缓存(如 HashMap)中,即使 Key 对应的对象已经没用了,只要缓存不清除,对象就永远不会被 GC 回收,容易造成内存泄漏。而使用弱引用作为 Key(如 JDK 提供的 WeakHashMap),当 Key 的外部强引用消失后,GC 会自动回收 Key,对应的 Value 也会从缓存中移除,不需要手动清理。 - 对象池:用于
管理对象池中的非核心对象,对象池本身用强引用持有核心对象,而用弱引用持有一些不常用、可重建的扩展对象。当内存紧张触发 GC 时,这些弱引用指向的对象会被回收,释放内存;真正需要时再重新创建。 - 避免内存泄漏:当一个对象不应该被长期引用时,使用弱引用可以防止该对象被意外地保留,从而
避免潜在的内存泄漏。例如ThreadLocalMap 的 Entry 使用弱引用指向 ThreadLocal 对象。当 ThreadLocal 外部强引用被置为 null 后,GC 会自动回收它,防止 ThreadLocal 本身泄漏。
- 缓存系统:适合
四、虚引用(Phantom Reference)
虚引用通过 java.lang.ref.PhantomReference 类实现,它是最弱的引用类型。
ReferenceQueue<MyObject>queue=newReferenceQueue<>();PhantomReference<MyObject>phantomRef=newPhantomReference<>(newMyObject(),queue);虚引用就像根本不存在的绳子。无论有没有虚引用,对象被 GC 回收时几乎不受影响。 虚引用必须和引用队列(ReferenceQueue)一起使用,它的 get() 方法永远返回 null。
虚引用的唯一作用,就是当对象被垃圾收集器回收时,能够收到一个系统通知。JVM 会将关联的虚引用加入到引用队列中,程序可以通过监控这个队列来得知对象即将被回收,从而在回收之后做一些资源清理(如释放堆外内存)。
- 适用场景:堆外内存管理,如 DirectByteBuffer,当 Java 堆内的对象被回收时,通过虚引用通知 JVM 去释放堆外的 native 内存
