引用和引用referent指向的对象(引用指向的对象)。每个引用对象都是围绕其引用对象构建的,并且不能更改引用对象。翻译比较简单。参考(referenceobject)是一个间接层。我们的代码访问引用(referent)指向的对象。应用程序代码、软/弱引用、引用对象之间的关系所有引用类型都是抽象类java.lang.ref.Reference的子类:该抽象类提供get方法获取引用指向的对象(r??eferent):对于示例:SoftReference>ref=newSoftReference>(newLinkedList());//在代码的其他地方,您创建了一个要添加到列表中的FooListlist=ref.get();if(list!=null){list.add(foo);}else{//列表不见了;dowhateverisappropriate}四个引用的定义我想大多数人都可以很容易的说出引用的定义:如果栈上一个变量存储的值代表了另一块内存的起始地址,则称该变量代表了一个对这块内存或这个对象的引用。在JDK1.2之前,没问题,这个定义是正确的。但现在看起来有点太窄了。比如我们希望引用可以描述这样一类对象:当内存空间足够时,将其保存在内存中。如果垃圾回收后内存空间紧张,那么这些对象将被丢弃以释放空间。对于上面的定义,一个对象只有“被引用”和“未被引用”两种状态,对于这种情况显然是无能为力的。因此,在JDK1.2之后,Java扩展了引用的概念,将引用分为以下四种。这四种参照物的力量逐渐减弱。所谓的“实力”,可以这么简单的理解。引用的强度越强,那么被引用的对象就越不容易被垃圾回收器回收:1)强引用,StronglyReference强引用随处可见,这是对“引用”最传统的定义,而通过new的引用赋值类似于Useruser=newUser()这种引用关系。只要仍然有强引用指向一个对象,就可以表明这个对象还“活着”,垃圾收集器永远不会碰这样的对象。也就是说,当内存空间不足时,JVM宁愿抛出OOM,导致程序异常终止,也不会回收强引用对象。2)SoftReferences,SoftReferences对应我们上面提到的例子,可以使对象免于一些垃圾回收,用来描述一些有用但不是必需的对象。如果内存空间足够,软引用不会被回收,但是如果即将发生OOM,JVM会回收这些软引用来释放空间。如果回收这些软引用后内存还是不够用,就会抛出OOM。JDK1.2之后提供了SoftReference类来实现软引用。3)弱引用,WeakReference弱引用也用来描述那些非本质的对象,但是它的强度比软引用要弱。如果你创建了一个只持有弱引用的对象,那么在下一次垃圾回收发生时,这个对象就会被回收,而不管当前内存是否足够。换句话说,与弱引用关联的对象只能存活到下一次垃圾回收发生。JDK1.2之后提供了WeakReference类来实现弱引用。4)Phantomreference,PhantomReferencePhantomreference也叫ghostreference,phantomreference,phantomreference,它是最弱的一种引用关系。如果一个对象只持有一个虚引用,那么它对其生命周期没有任何影响,就像没有引用一样,我们无法通过虚引用获取对象实例(见下图,其get方法总是返回null)。幻引用的get方法很搞笑,那么幻引用有什么用呢?事实上,我们可以通过为一个对象设置一个虚引用关联来跟踪一个对象被垃圾回收的活动(详见下面的解释)。JDK1.2之后提供了PhantomReference类来实现虚引用。在JDK1.2之前,一个对象的生命周期可以简单的用下图来表示:objectlife-cycle,没有引用对象在JDK1.2中,引入了java.lang.ref包,新增了三个状态(stage)在一个对象的生命周期中:可以看到,除了强引用对应的强可达状态外,还增加了三个额外的状态,分别对应软引用、弱引用和幻象引用(phantomreferences):softlyreachable、soft可达:当我们只能通过软引用访问对象的状态时。Weaklyreachable,weaklyreachable:是无法通过强引用或软引用访问,只能通过弱引用访问的状态。Phantomreachable,幻影可达:上面的流程图已经很直观了,就是没有强、软、弱引用关联,只有当幻影引用指向这个对象时才会被回收。除了幻象引用(因为get总是返回null),如果对象还没有被销毁,可以通过get方法获取到原始对象。这意味着通过使用软引用和弱引用,我们可以将访问的对象重定向到强引用,也就是人为的改变对象的可访问状态!这就是为什么上图中有些地方画了双向箭头。ReferenceQueueReferenceQueueReferenceQueue是用来和引用一起工作的,最常和幻引用一起使用,因为幻引用的构造函数必须指定一个引用队列,而其他引用类型可以在没有引用队列的情况下运行。当一个被引用的对象(r??eferent)被回收时,JVM会把它的引用(reference)加入到引用队列的末尾,相当于一个通知机制。这个操作实际上是由ReferenceHandler守护线程完成的,它是在Reference静态代码块中创建并运行的线程,所以只要初始化父类Reference,就会创建并运行该线程,其运行方法依赖于更多本地(原生)方法:由于ReferenceHandler是一个守护线程,除非JVM进程终止,否则它将一直在后台运行(注意它的run()方法使用了无限循环)。其实就是调用了引用队列的enqueue方法来执行入队操作:这样我们就可以通过ReferenceQueue中的元素(references)知道哪些对象(被引用对象)被回收了。这样,我们就可以在对象被回收之后,做一些我们想做的事情。这就是为什么幻影引用的唯一目的是跟踪被垃圾收集的对象的活动。另外,ReferenceQueue提供了三种出栈头元素的方法:poll():用于取出并返回队列中的下一个引用对象,如果队列为空则返回null;remove():用于移除并返回队列中的下一个引用对象,该方法会阻塞直到队列返回一个可用的引用对象;remove(longtimeout):用于移除并返回队列中的下一个引用对象。此方法会阻塞,直到队列返回可用的引用对象,或在指定的超时后终止。如果超过指定的超时,则返回null。如果指定超时为0,则表示无限期等待。不同引用类型的应用场景软引用的应用:CircuitBreaker,CircuitBreaker可怕的OutOfMemoryError。比如下面JDBC代码的逻辑是查询数据库中的多行数据。极端情况下,如果查询的数据有一百万行,而你系统可用的内存资源不足以容纳这百万行数据,这时候程序肯定会报错。这时候软引用的价值就体现出来了:如果JVM在查询数据的过程中内存不足,就会释放软引用指向的对象的内存,为新的数据腾出空间,而在同时在业务线程上面,我们可以抛出自定义异常,以便我们进行程序的后续处理:弱引用的应用:ThreadLocal的ThreadLocalMap实现是众所周知的。幻引用的应用:数据库连接池数据库连接池应该具备的优点之一就是可以有效避免连接资源泄漏,回收连接资源:下面这个类可以忽略,但是有一点值得注意,用户连接业务线程在使用连接池时得到的对象就是这个PooledConnection对象,而不是真正的Connection对象。重点关注下面这个类的实现:如果在引用队列中能够获取到引用,说明这个连接对象已经被GC丢弃了。这时候,我们应该对连接池执行相应的清理逻辑(重点关注下面的releaseConnection方法):看起来挺复杂的,其实本质上还是围绕着幻引用的特性:你不能通过它访问对象,但是它结合引用队列提供了一种对象回收后做某些事情的机制。