Java引用类型有四种:强、软、弱、虚灵
强引用:
强引用和其他三种引用不同,强引用在在内存中(VM栈中的栈帧上、堆中对象实例分配的空间、方法区静态引用变量)占用4个字节,类似于基本类型,不过基本类型存储的是本身变量的值,而强引用类型存储的是指向对象的地址(或者是索引地址)。
而其他三类引用类型都是以类的形式呈现的,其继承结构如下:
三者的使用方式都是类似的:
(1):定义一个普通类型的强引用指向该类型的实例(以String为例):
StringaString=new String(“Example”);
(2)定义一个软/弱/虚引用类型的强引用:
SoftReference<String>Stringref;
(3)将普通类型的强引用传入软/弱/虚引用实例;
Stringref=new SoftReference<String>( aString);
(4)将原普通类型的强引用指向NULL;
aString=NULL;
这样我们就由直接持有对实例的强引用变为持有对一个软引用实例的强引用,这个强引用实例则持有对原对象的引用。
对于软引用:
在堆中内存不足的情况下,如果GC发现某个实例是软引用类型的实例,就会把这个软引用类型实例持有的普通对象回收掉,即这个软引用类型实例变成了”死项“;因此我们就需要方法可以清除这些死项。
Java中提供了一个引用队列类(上图右边),我们可以构建一个全局的引用队列实例,在我们构建一个软引用实例时传入这个引用队列,这样当软引用类型实例变成了”死项“时,系统会自动把这个软引用类型实例的引用加入到这个队列中,系统就可以根据这个队列中内容清除死项。
对于弱引用:
在系统进行GC时,如果GC发现某个实例是弱引用类型的实例,无论堆中内存是否充足,都会把这个弱引用类型实例持有的普通对象回收掉,死项清除同软引用。
对于虚引用:
虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
为什么需要使用软引用:
(1)使用软引用构建敏感数据的缓存
使用弱引用构建非敏感数据的缓存