为什么Java有4种不同类型的引用?

Ami*_*mar 5 java oop garbage-collection reference-type java-8

直到今天,我才意识到 Java 有四种主要的引用类型。

\n
    \n
  1. 强引用:默认引用类型Java
  2. \n
  3. 弱引用:如果一个对象具有弱引用,则GC即使有足够的内存,也会在下次运行时回收该对象\xe2\x80\x99s内存。
  4. \n
  5. 软引用:如果一个对象有软引用,那么GC只有当它急需一些内存时才回收这个对象\xe2\x80\x99s内存。
  6. \n
  7. 幻像引用:如果一个对象有幻像引用,那么它就符合垃圾回收的条件。但是,在 GC 之前,JVM 将应该被垃圾收集的对象放入一个名为 的队列中reference queue
  8. \n
\n

我理解了基本概念,并编写了一个小程序来理解每种引用类型的工作原理。

\n
import java.lang.ref.PhantomReference;\nimport java.lang.ref.ReferenceQueue;\nimport java.lang.ref.SoftReference;\nimport java.lang.ref.WeakReference;\n\nclass User \n{ \n    public User info() \n    { \n        System.out.println("Info method invoked from User class");\n        return null;\n    }   \n} \n\npublic class ReferencesExample \n{ \n    public static void main(String[] args) \n    { \n        //Strong Reference\n        User userRefObj = new User(); \n        System.out.println("1 :" + userRefObj.info());\n\n        // Weak Reference\n        WeakReference<User> weakref = new WeakReference<User>(userRefObj.info());  \n        System.out.println("2 : " + weakref);\n\n        // Soft Reference    \n        SoftReference<User> softref = new SoftReference<User>(userRefObj.info());  \n        System.out.println("3 : " + softref);\n\n        // Phantom Reference \n        ReferenceQueue<User> refQueueObj = new ReferenceQueue<User>(); \n        PhantomReference<User> phantomRef = new PhantomReference<User>(userRefObj.info(),refQueueObj); \n        System.out.println("4 : " + phantomRef);     \n       \n    } \n}\n
Run Code Online (Sandbox Code Playgroud)\n

输出 :

\n
1 :null\nInfo method invoked from User class\nInfo method invoked from User class\n2 : java.lang.ref.WeakReference@15db9742\nInfo method invoked from User class\n3 : java.lang.ref.SoftReference@6d06d69c\nInfo method invoked from User class\n4 : java.lang.ref.PhantomReference@7852e922\n
Run Code Online (Sandbox Code Playgroud)\n

疑问:在现实场景中,我们如何决定使用哪种引用类型以及在何处使用?

\n

Eug*_*ene 2

这是一个复杂的答案,尤其是“现实世界”部分。这些特殊的参考文献是一个(非常)锋利的工具,应该很少接触它并有很好的理解。您的第一个误解是只Phantom References使用queue(称为ReferenceQueue)。事实上,他们使用queue. PhantomReference其中有点“怪异”,主要是因为它周围的规范已经从java-8变为java-9. 您可以阅读此答案以获取一些详细信息java-8(目前尚不清楚保持实例处于活动状态的原因)。

那么您得到的常见误解是“下次运行”,有关更多详细信息,您可以查看此处。这里的“第二个”或“下一个”的概念有点棘手。但关键是这是不确定的。

提供“现实世界”的例子也有点棘手。发生这种情况是因为您很少直接使用这些引用,它们通常预先打包在实用程序中。例如,您可以了解 WeakHashMap 的工作原理(直接使用WeakReferenceReferenceQueue在底层),或者事件此答案guava尽管咖啡因CacheBuilder曾经提供一些处理SoftReferences(但不再是)的功能, 但它仍然可以

PhantomReferences在内部用于Cleaner API(since java-9)。是一个显示其一般用法的示例。如果没有PhantomReferences,这实际上是不可能的(至少不是那么“容易”)。


从这个意义上说,我们WeakHashMap在生产中使用(我们也使用Cleaner API,但少得多)。如果你真的想了解它们,你需要了解它们是如何garbage collector工作的(比如,真正的工作原理),然后阅读他们的官方文档并尝试(并询问)多种事情。