如果我们希望引用能够描述这样一类对象:当内存空间还足够时,就保留在内存之中,如果垃圾收集后内存空间比较紧张,那就抛弃这些对象释放空间。
对于上述的定义来说,一个对象只有 “被引用” 和 “未被引用” 两种状态,对这种情况显然是无能无力的。
不同的引用类型,主要体现的是对象不同的可达性(reachable)状态和对垃圾收集的影响。
User user = new User()。对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为 null,就是可以被垃圾收集的了,当然具体回收时机还是要看垃圾收集策略。JDK1.2之前对象的生命周期:

JDK1.2后对象使用了四种引用类型,对象的生命周期如下所示:

这是 Java 定义的不同可达性级别(reachability level),具体如下:
当然,还有一个最后的状态,就是不可达(unreachable),意味着对象可以被清除了。
我们可以在利用软引用和弱引用,将访问到的对象,重新指向强引用,也就是人为的改变了对象的可达性状态。
判断对象可达性,是 JVM 垃圾收集器决定如何处理对象的一部分考虑。
所有的引用类型,都是抽象类 java.lang.ref.Reference 的子类,这个抽象类提供了 get 方法用来获取引用指向的对象(referent)
SoftReference<List<Foo>> ref =new SoftReference<List<Foo>>(newLinkedList<Foo>());
List<Foo>list = ref.get();
if (list!=null) {
list.add(foo);
} else {
//listisgone;dowhateverisappropriate
}
**对于幻象引用,我们无法通过幻象引用来取得一个对象实例,也就是说 get() 方法永远返回 null。**对于其他引用对象,如果还没有被销毁,都可以通过 get 方法获取原有对象。
谈到各种引用的编程,就必然要提到引用队列ReferenceQueue ,引用队列主要用来配合引用工作。我们在创建各种引用并关联到响应对象时,可以选择是否需要关联引用队列,JVM 会在特定时机将引用 enqueue 到队列里,我们可以从队列里获取引用(remove 方法在这里实际是有获取的意思)进行相关后续逻辑。
其中幻象引用由于get 方法只返回 null,构造函数必须指定引用队列,因此必须和引用队列一起使用。
当某个被引用的对象(referent)被回收的时候,JVM 会将指向它的引用(reference)加入到引用队列的队列末尾,这可以作为一种通知机制。这个功能是由 ReferenceHandler 守护线程来做的,这个守护线程是在 Reference 静态代码块中建立并且运行的线程,所以只要 Reference 这个父类被初始化,该线程就会创建和运行。
我们可以通过 ReferenceQueue 中的元素(引用)来知道哪些对象(被引用的对象)被回收掉了,通过这种方式,我们就可以在对象被回收掉之后,做一些我们自己想做的事情。比如文章一开始提到的使用幻象引用监控对象的创建和销毁。