Java里的引用

什么是Java里的引用

引用可以理解为指针

有什么用

不同引用不同用途
强引用
软引用
弱引用
虚引用

Java中引用实现

package java.lang.ref;

import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.HotSpotIntrinsicCandidate;
import jdk.internal.access.JavaLangRefAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.ref.Cleaner;

/**
 * Abstract base class for reference objects.  This class defines the
 * operations common to all reference objects.  Because reference objects are
 * implemented in close cooperation with the garbage collector, this class may
 * not be subclassed directly.
 *
 * @author   Mark Reinhold
 * @since    1.2
 */

public abstract class Reference<T> {

}
/* The state of a Reference object is characterized by two attributes.  It
 * may be either "active", "pending", or "inactive".  It may also be
 * either "registered", "enqueued", "dequeued", or "unregistered".
 *
 *   Active: Subject to special treatment by the garbage collector.  Some
 *   time after the collector detects that the reachability of the
 *   referent has changed to the appropriate state, the collector
 *   "notifies" the reference, changing the state to either "pending" or
 *   "inactive".
 *   referent != null; discovered = null, or in GC discovered list.
 *
 *   Pending: An element of the pending-Reference list, waiting to be
 *   processed by the ReferenceHandler thread.  The pending-Reference
 *   list is linked through the discovered fields of references in the
 *   list.
 *   referent = null; discovered = next element in pending-Reference list.
 *
 *   Inactive: Neither Active nor Pending.
 *   referent = null.
 *
 *   Registered: Associated with a queue when created, and not yet added
 *   to the queue.
 *   queue = the associated queue.
 *
 *   Enqueued: Added to the associated queue, and not yet removed.
 *   queue = ReferenceQueue.ENQUEUE; next = next entry in list, or this to
 *   indicate end of list.
 *
 *   Dequeued: Added to the associated queue and then removed.
 *   queue = ReferenceQueue.NULL; next = this.
 *
 *   Unregistered: Not associated with a queue when created.
 *   queue = ReferenceQueue.NULL.
 *
 * The collector only needs to examine the referent field and the
 * discovered field to determine whether a (non-FinalReference) Reference
 * object needs special treatment.  If the referent is non-null and not
 * known to be live, then it may need to be discovered for possible later
 * notification.  But if the discovered field is non-null, then it has
 * already been discovered.
 *
 * FinalReference (which exists to support finalization) differs from
 * other references, because a FinalReference is not cleared when
 * notified.  The referent being null or not cannot be used to distinguish
 * between the active state and pending or inactive states.  However,
 * FinalReferences do not support enqueue().  Instead, the next field of a
 * FinalReference object is set to "this" when it is added to the
 * pending-Reference list.  The use of "this" as the value of next in the
 * enqueued and dequeued states maintains the non-active state.  An
 * additional check that the next field is null is required to determine
 * that a FinalReference object is active.
 *
 * Initial states:
 *   [active/registered]
 *   [active/unregistered] [1]
 *
 * Transitions:
 *                            clear
 *   [active/registered]     ------->   [inactive/registered]
 *          |                                 |
 *          |                                 | enqueue [2]
 *          | GC              enqueue [2]     |
 *          |                -----------------|
 *          |                                 |
 *          v                                 |
 *   [pending/registered]    ---              v
 *          |                   | ReferenceHandler
 *          | enqueue [2]       |--->   [inactive/enqueued]
 *          v                   |             |
 *   [pending/enqueued]      ---              |
 *          |                                 | poll/remove
 *          | poll/remove                     |
 *          |                                 |
 *          v            ReferenceHandler     v
 *   [pending/dequeued]      ------>    [inactive/dequeued]
 *
 *
 *                           clear/enqueue/GC [3]
 *   [active/unregistered]   ------
 *          |                      |
 *          | GC                   |
 *          |                      |--> [inactive/unregistered]
 *          v                      |
 *   [pending/unregistered]  ------
 *                           ReferenceHandler
 *
 * Terminal states:
 *   [inactive/dequeued]
 *   [inactive/unregistered]
 *
 * Unreachable states (because enqueue also clears):
 *   [active/enqeued]
 *   [active/dequeued]
 *
 * [1] Unregistered is not permitted for FinalReferences.
 *
 * [2] These transitions are not possible for FinalReferences, making
 * [pending/enqueued] and [pending/dequeued] unreachable, and
 * [inactive/registered] terminal.
 *
 * [3] The garbage collector may directly transition a Reference
 * from [active/unregistered] to [inactive/unregistered],
 * bypassing the pending-Reference list.
 */

private T referent;         /* Treated specially by GC */

/* The queue this reference gets enqueued to by GC notification or by
 * calling enqueue().
 *
 * When registered: the queue with which this reference is registered.
 *        enqueued: ReferenceQueue.ENQUEUE
 *        dequeued: ReferenceQueue.NULL
 *    unregistered: ReferenceQueue.NULL
 */
volatile ReferenceQueue<? super T> queue;

/* The link in a ReferenceQueue's list of Reference objects.
 *
 * When registered: null
 *        enqueued: next element in queue (or this if last)
 *        dequeued: this (marking FinalReferences as inactive)
 *    unregistered: null
 */
@SuppressWarnings("rawtypes")
volatile Reference next;

/* Used by the garbage collector to accumulate Reference objects that need
 * to be revisited in order to decide whether they should be notified.
 * Also used as the link in the pending-Reference list.  The discovered
 * field and the next field are distinct to allow the enqueue() method to
 * be applied to a Reference object while it is either in the
 * pending-Reference list or in the garbage collector's discovered set.
 *
 * When active: null or next element in a discovered reference list
 *              maintained by the GC (or this if last)
 *     pending: next element in the pending-Reference list (null if last)
 *    inactive: null
 */
private transient Reference<T> discovered;
/* -- Referent accessor and setters -- */

/**
 * Returns this reference object's referent.  If this reference object has
 * been cleared, either by the program or by the garbage collector, then
 * this method returns {@code null}.
 *
 * @return   The object to which this reference refers, or
 *           {@code null} if this reference object has been cleared
 */
@HotSpotIntrinsicCandidate
public T get() {
    return this.referent;
}
/**
 * Clears this reference object.  Invoking this method will not cause this
 * object to be enqueued.
 *
 * <p> This method is invoked only by Java code; when the garbage collector
 * clears references it does so directly, without invoking this method.
 */
public void clear() {
    this.referent = null;
}

强引用 StrongReference

强引用 Object obj = new Object();
上述Object这类对象就具有强引用,属于不可回收的资源,垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠回收具有强引用的对象,来解决内存不足的问题。
如果想中断或者回收强引用对象,可以显式地将引用赋值为null,这样的话JVM就会在合适的时间,进行垃圾回收。

软引用 SoftReference

如果一个对象只具有软引用,那么它的性质属于可有可无的那种。如果此时内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。

软引用可用来实现内存敏感的告诉缓存。软引用可以和一个引用队列联合使用,如果软件用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
当内存不足时,软引用对象被回收时,reference.get()为null,此时软引用对象的作用已经发挥完毕,这时将其添加进ReferenceQueue 队列中

Object obj = new Object();
ReferenceQueue queue = new ReferenceQueue();
SoftReference reference = new SoftReference(obj, queue);
//强引用对象滞空,保留软引用
obj = null;
/**
 * Soft reference objects, which are cleared at the discretion of the garbage
 * collector in response to memory demand.  Soft references are most often used
 * to implement memory-sensitive caches.
 *
 * <p> Suppose that the garbage collector determines at a certain point in time
 * that an object is <a href="package-summary.html#reachability">softly
 * reachable</a>.  At that time it may choose to clear atomically all soft
 * references to that object and all soft references to any other
 * softly-reachable objects from which that object is reachable through a chain
 * of strong references.  At the same time or at some later time it will
 * enqueue those newly-cleared soft references that are registered with
 * reference queues.
 *
 * <p> All soft references to softly-reachable objects are guaranteed to have
 * been cleared before the virtual machine throws an
 * {@code OutOfMemoryError}.  Otherwise no constraints are placed upon the
 * time at which a soft reference will be cleared or the order in which a set
 * of such references to different objects will be cleared.  Virtual machine
 * implementations are, however, encouraged to bias against clearing
 * recently-created or recently-used soft references.
 *
 * <p> Direct instances of this class may be used to implement simple caches;
 * this class or derived subclasses may also be used in larger data structures
 * to implement more sophisticated caches.  As long as the referent of a soft
 * reference is strongly reachable, that is, is actually in use, the soft
 * reference will not be cleared.  Thus a sophisticated cache can, for example,
 * prevent its most recently used entries from being discarded by keeping
 * strong referents to those entries, leaving the remaining entries to be
 * discarded at the discretion of the garbage collector.
 *
 * @author   Mark Reinhold
 * @since    1.2
 */

public class SoftReference<T> extends Reference<T> {

}
/**
 * Returns this reference object's referent.  If this reference object has
 * been cleared, either by the program or by the garbage collector, then
 * this method returns {@code null}.
 *
 * @return   The object to which this reference refers, or
 *           {@code null} if this reference object has been cleared
 */
public T get() {
    T o = super.get();
    if (o != null && this.timestamp != clock)
        this.timestamp = clock;
    return o;
}

弱引用 WeakReference

如果一个对象具有弱引用,那其的性质也是可有可无的状态。

而弱引用和软引用的区别在于:弱引用的对象拥有更短的生命周期,只要垃圾回收器扫描到它,不管内存空间充足与否,都会回收它的内存。

同样的弱引用也可以和引用队列一起使用。

Object obj = new Object();
ReferenceQueue queue = new ReferenceQueue();
WeakReference reference = new WeakReference(obj, queue);
//强引用对象滞空,保留软引用
obj = null;
/**
 * Weak reference objects, which do not prevent their referents from being
 * made finalizable, finalized, and then reclaimed.  Weak references are most
 * often used to implement canonicalizing mappings.
 *
 * <p> Suppose that the garbage collector determines at a certain point in time
 * that an object is <a href="package-summary.html#reachability">weakly
 * reachable</a>.  At that time it will atomically clear all weak references to
 * that object and all weak references to any other weakly-reachable objects
 * from which that object is reachable through a chain of strong and soft
 * references.  At the same time it will declare all of the formerly
 * weakly-reachable objects to be finalizable.  At the same time or at some
 * later time it will enqueue those newly-cleared weak references that are
 * registered with reference queues.
 *
 * @author   Mark Reinhold
 * @since    1.2
 */

public class WeakReference<T> extends Reference<T> {

}

虚引用(PhantomReference)

虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。

注意:虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之关联的引用队列中。

程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

Object obj = new Object();
ReferenceQueue queue = new ReferenceQueue();
PhantomReference reference = new PhantomReference(obj, queue);
//强引用对象滞空,保留软引用
obj = null;
package java.lang.ref;


/**
 * Phantom reference objects, which are enqueued after the collector
 * determines that their referents may otherwise be reclaimed.  Phantom
 * references are most often used to schedule post-mortem cleanup actions.
 *
 * <p> Suppose the garbage collector determines at a certain point in time
 * that an object is <a href="package-summary.html#reachability">
 * phantom reachable</a>.  At that time it will atomically clear
 * all phantom references to that object and all phantom references to
 * any other phantom-reachable objects from which that object is reachable.
 * At the same time or at some later time it will enqueue those newly-cleared
 * phantom references that are registered with reference queues.
 *
 * <p> In order to ensure that a reclaimable object remains so, the referent of
 * a phantom reference may not be retrieved: The {@code get} method of a
 * phantom reference always returns {@code null}.
 *
 * @author   Mark Reinhold
 * @since    1.2
 */

public class PhantomReference<T> extends Reference<T> {

}
/**
 * Returns this reference object's referent.  Because the referent of a
 * phantom reference is always inaccessible, this method always returns
 * {@code null}.
 *
 * @return {@code null}
 */
public T get() {
    return null;
}