Java中的引用类型

       Java 中的引用类型我们都知道有 强引用、软引用(SoftReference)、弱引用(WeakReference)、虚引用(PhantomReference),除此之外,今天翻看JDK 8 【jdk1.8.0_172】源码时,还看到一种 FinalReference ,只不过这种引用类型是提供给JVM使用的,自己编程写代码用不上的。

java.lang.ref

      Java 中引用相关的类定义在 java.lang.ref 包中,类图如下:

Java中的引用类型_第1张图片

        FinalReference、PhantomReference、WeakReference、SoftReference 类都继承抽象类Reference。引用队列类ReferenceQueue,在检测到适当的可到达性更改后,垃圾回收器将已注册的引用对象添加到该队列中。FinalizerHistogram类适用于 GC.finalizer_info 诊断命令支持,由VM调用。Java中的引用类型设计是跟垃圾回收器密切相关的。

强引用

       强引用类型就是我们平常开发最普遍使用的,比如有个学生类Student,"Student s = new Student();",s 和new 出来的对象之间的关系就是强引用关系,只要强引用关系还存在,Java垃圾收集器就不会回收该对象。

软引用

       软引用是用来描述程序中有用但是并非必需的对象。软引用对象,垃圾回收器会根据内存需求酌情清除这些对象。 软引用最常用于实现对内存敏感的缓存。对于软引用关联的对象,在系统将要发生内存溢出异常(OutOfMemoryError)之前,将会回收这些软引用对象。如果回收之后还没有足够内存,才会跑出内存溢出异常。

       JDK 中使用SoftReference 类实现软引用。

构造方法:

//创建引用给定对象的新的软引用。
SoftReference(T referent)

//创建一个引用给定对象的新的软引用,并向给定队列注册该引用。
SoftReference(T referent, ReferenceQueue q)

继承自Reference类的方法 get(),用于返回此软引用对象的指示对象:

/**
     * 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 null.
     * 
     * 返回此引用对象的引用对象。 如果此引用对象已被程序或垃圾收集器清除,然后
     * 此方法返回 null 。
     *
     * @return   The object to which this reference refers, or
     *           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;
    }

弱引用

       弱引用对象也是用来描述程序中非必需的对象,但是它比软引用关系更弱。如果一个对象只被弱引用关联,那么它只能存活到下一次垃圾回收之前。Java垃圾回收器进行回收时,无论当前内存是否足够都会清理回收只被弱引用关联的对象。弱引用最常用于实现规范化映射。

       JDK中使用WeakReference类实现弱引用:

public class WeakReference extends Reference {

    /**
     * Creates a new weak reference that refers to the given object.  The new
     * reference is not registered with any queue.
     * 创建引用给定对象的新的弱引用。
     * @param referent object the new weak reference will refer to
     */
    public WeakReference(T referent) {
        super(referent);
    }

    /**
     * Creates a new weak reference that refers to the given object and is
     * registered with the given queue.
     * 创建引用给定对象的新的弱引用,并向给定队列注册该引用。
     * @param referent object the new weak reference will refer to
     * @param q the queue with which the reference is to be registered,
     *          or null if registration is not required
     */
    public WeakReference(T referent, ReferenceQueue q) {
        super(referent, q);
    }

}

有道面试题,可以加深对弱引用的理解:

    public String test(){
        String a = new String("a");
        WeakReference b = new WeakReference(a);
        WeakHashMap weakMap = new WeakHashMap();
        weakMap.put(b.get(), 1);
        a = null;
        System.gc();
        String c = "";
        try{
            c = b.get().replace("a", "b");
            return c;
        }catch(Exception e){
            c = "c";
            return c;
        }finally{
            c += "d";
            return c + "e";
        }
    }

程序输出结果:

cde

大家可以分析一下,加深理解。

虚引用

       虚引用是最弱的一种引用关系,一个对象是否有虚引用的存在,完全不会对其生命周期构成影响,也用法无法通过虚引用获取对象。为了确保可回收的对象仍然保持原状,虚引用的指示对象不能被获取:虚引用的 get 方法总是返回 null。文档说虚引用最常见的用法是以某种可能比使用 Java finalization机制更灵活的方式来指派 pre-mortem 清除动作。

public class PhantomReference extends Reference {

    /**
     * Returns this reference object's referent.  Because the referent of a
     * phantom reference is always inaccessible, this method always returns
     * null.
     * 返回此引用对象的指示对象。因为虚引用的指示对象总是不可到达的,所以此方法总是返回 null。
     *
     * @return  null
     */
    public T get() {
        return null;
    }

    /**
     * Creates a new phantom reference that refers to the given object and
     * is registered with the given queue.
     * 创建一个引用给定对象的新的虚引用,并向给定队列注册它。
     *
     * 

It is possible to create a phantom reference with a null * queue, but such a reference is completely useless: Its get * method will always return null and, since it does not have a queue, it * will never be enqueued. * 可能用一个 null 队列创建虚引用,但这样的引用是完全无用的:其 get 方法将总是返回 null, * 同时,因为它没有队列,所以将永远无法把它加入队列中。 * * @param referent the object the new phantom reference will refer to * @param q the queue with which the reference is to be registered, * or null if registration is not required */ public PhantomReference(T referent, ReferenceQueue q) { super(referent, q); } }

       从构造方法中可以看出,PhantomReference 通常和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要进行垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。功能类似一种对象被垃圾回收器收集回收之前的通知。

FinalReference

       FinalReference 是提供给Java虚拟机使用的,用于垃圾回收相关功能。该类和子类Finalizer访问权限都是同包访问(Package-private)的。InfoQ上有篇文章讲的很详细:JVM 源码分析之 FinalReference 完全解读

你可能感兴趣的:(Java)