你真的知道Java中的4种引用类型吗()

本文概述

  • 1. FinalReference
  • 2.软引用
  • 3.弱引用
  • 4.PhantomReference
  • 5, WeakHashMap类及其实现
Java提供了四个级别的引用:SoftReference, FinalReference, WeakReference和PhantomReference。在这四种引用类型中, 只有FinalReference类在包中可见, 而其他三种引用类型都是公共的, 可以直接在应用程序中使用。参考类型的类结构如图所示。
你真的知道Java中的4种引用类型吗()

文章图片
1. FinalReference Java中的引用类似于C中的指针。并且你可以通过引用对堆中的对象进行操作。这是一个例子:
StringBuffer stringBuffer = new StringBuffer("Helloword");

变量str指向StringBuffer实例所在的堆空间, 你可以使用str操纵对象。
你真的知道Java中的4种引用类型吗()

文章图片
这是FinalReferences的功能:
  1. FinalReferences提供对目标对象的直接访问。
  2. FinalReferences指向的对象不会在任何时候被系统回收。 JVM会抛出OOM异常, 而不是回收FinalReference指向的对象。
  3. FinalReferences可能会导致内存泄漏。
2.软引用 除FinalReference外, SoftReference是最强的引用类型。可以通过java.lang.ref.SoftReference使用SoftReferences。 JVM不会快速回收持有SoftReference的对象。 JVM将根据当前堆的使用情况确定何时回收。仅当堆使用率接近阈值时, 才会收集SoftReferenced对象。因此, SoftReference可用于实现对内存敏感的缓存。
SoftReference的特征是可以保留对Java对象的软引用的实例。软引用的存在不会阻止垃圾回收线程回收Java对象。这意味着一旦SoftReference保存了对Java对象的软引用, 在GC线程回收Java对象之前, SoftReference类提供的get()方法将返回对该Java对象的强引用。一旦GC线程回收了Java对象, get()方法将返回null。
以下是如何使用SoftReferences的示例。
在你的IDE中设置参数-Xmx2m -Xms2m, 并将堆内存大小指定为2m。
@Test public void test3(){ MyObject obj = new myObject(); SoftReference sf = new SoftReference< > (obj); obj = null; System.gc(); //byte[] bytes = new byte[1024*100]; //System.gc(); System.out.println("Is Collected: "+sf.get()); }

结果如下:
Is Collected: cn.zyzpp.MyObject@42110406

打开注释的语句new byte [1024 * 100], 该语句请求一个大的堆空间块, 从而使堆内存变得紧张。再次显式调用GC, 结果如下:
Is Collected: null

请注意, 在系统内存不足的情况下, SoftReferences将被回收。
3.弱引用 WeakReference是一种参考类型, 比SoftReference弱。在GC系统中, 无论何时找到弱引用, 无论系统堆空间是否足够, 对象都将被回收。而且, 你可以使用java.lang.ref.WeakReference实例来保存对Java对象的弱引用。
public void test3(){ MyObject obj = new MyObject(); WeakReference sf = new WeakReference(obj); obj = null; System.out.println("Is Collected: "+sf.get()); System.gc(); System.out.println("Is Collected: "+sf.get()); }

结果如下:
Is Collected: cn.zyzpp.MyObject@42110406 Is Collected: null

SoftReference和WeakReference非常适合用于保存可选的缓存数据。如果使用它们, 则在系统内存不足时, 将回收缓存的数据而不会引起内存溢出。当内存资源足够时, 缓存的数据可以存在很长时间, 这将加速系统。
4.PhantomReference PhantomReference是所有类型中最弱的。持有PhantomReference的对象几乎与没有引用相同, 并且可以随时由垃圾收集器回收。当尝试通过PhantomReferences的get()方法获得强大的引用时, 它将始终失败。并且PhantomReferences必须与参考队列一起使用, 以跟踪垃圾回收过程。
当垃圾回收器要回收对象时, 如果发现有一个PhantomReference, 它将在垃圾回收后销毁该对象, 并将PhantomReference添加到引用队列中。根据判断是否已向引用队列中添加了PhantomReference, 程序可以确定是否需要对引用的对象进行垃圾回收。如果程序发现PhantomReference已添加到引用队列中, 则将在回收引用对象的内存之前采取必要的措施。
public void test3(){ MyObject obj = new MyObject(); ReferenceQueue< Object> referenceQueue = new ReferenceQueue< > (); PhantomReference sf = new PhantomReference< > (obj, referenceQueue); obj = null; System.out.println("Is Collected: "+sf.get()); System.gc(); System.out.println("Is Collected: "+sf.get()); }

结果如下:
Is Collected: null Is Collected: null

PhantomReference上的get()操作始终返回null, 因为sf.get()方法的实现如下:
public T get() { return null; }

5, WeakHashMap类及其实现 WeakHashMap类位于java.util包中。它实现了Map接口, 并且是HashMap的实现。它使用WeakReferences作为内部数据的存储方案。 WeakHashMap是弱引用的典型应用程序, 可以用作简单的缓存表解决方案。
以下两段代码分别使用WeakHashMap和HashMap保存大量数据:
@Test public void test4(){ Map map; map = new WeakHashMap< String, Object> (); for (int i =0; i< 10000; i++){ map.put("key"+i, new byte[i]); } //map = new HashMap< String, Object> (); //for (int i =0; i< 10000; i++){ //map.put("key"+i, new byte[i]); //} }

它使用-Xmx2M来限制堆内存。使用WeakHashMap的代码结束运行, 并且使用HashMap的代码段引发异常。
java.lang.OutOfMemoryError: Java heap space

可以看出, 当系统内存不足时, WeakHashMap将使用WeakReferences, 并自动释放保存WeakReferences的内存数据。
【你真的知道Java中的4种引用类型吗()】但是, 如果WeakHashMap的键都在系统中都保留了FinalReferences, 则WeakHashMap将退化为普通的HashMap, 因为无法自动清除所有项目。

    推荐阅读