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

Why Java has 4 different types of references?

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

  1. 强引用 : Java 使用的默认引用类型。
  2. 弱引用 : 如果一个对象有一个弱引用,那么 GC 会在下一个 运行 回收这个对象的内存,即使有足够的内存。
  3. 软引用 : 如果一个对象有一个软引用,那么GC只有当它非常需要一些内存时才会回收这个对象的内存。
  4. Phantom Reference : 如果一个对象有一个 phantom 引用,那么它就有资格进行垃圾回收。但是,在 GC 之前,JVM 将应该被垃圾收集的对象放入一个名为 reference queue.
  5. 的队列中

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

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;

class User 
{ 
    public User info() 
    { 
        System.out.println("Info method invoked from User class");
        return null;
    }   
} 

public class ReferencesExample 
{ 
    public static void main(String[] args) 
    { 
        //Strong Reference
        User userRefObj = new User(); 
        System.out.println("1 :" + userRefObj.info());

        // Weak Reference
        WeakReference<User> weakref = new WeakReference<User>(userRefObj.info());  
        System.out.println("2 : " + weakref);

        // Soft Reference    
        SoftReference<User> softref = new SoftReference<User>(userRefObj.info());  
        System.out.println("3 : " + softref);

        // Phantom Reference 
        ReferenceQueue<User> refQueueObj = new ReferenceQueue<User>(); 
        PhantomReference<User> phantomRef = new PhantomReference<User>(userRefObj.info(),refQueueObj); 
        System.out.println("4 : " + phantomRef);     
       
    } 
}

输出:

1 :null
Info method invoked from User class
Info method invoked from User class
2 : java.lang.ref.WeakReference@15db9742
Info method invoked from User class
3 : java.lang.ref.SoftReference@6d06d69c
Info method invoked from User class
4 : java.lang.ref.PhantomReference@7852e922

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

事实答案很简单:因为仅靠强引用是不够的。在现实世界的生产代码中,您肯定需要一些弱引用的概念。

然后有人可能会争辩说其他类型只是过度工程化。该语言的设计者认为这些是有帮助的,但除了非常晦涩的情况外,它们并非如此。但请注意:相应的语义不能用普通的 java 代码来完成。所以这是其中一种情况“让我们把它添加到语言中以备不时之需”。

但是第二段很容易被视为意见,而不是事实。

提供这个答案很复杂,尤其是“真实世界”部分。这些特殊的参考文献是一个(非常)锋利的工具,应该很少接触并且有很好的理解。您的第一个误解是只有 Phantom References 使用 queue(称为 ReferenceQueue)。事实上,他们全部使用一个queuePhantomReference 在其中有点“怪异”,主要是因为围绕它的规范已从 java-8 更改为 java-9。您可以阅读(目前尚不清楚在java-8中保持实例存活的原因)。

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

提供“真实世界”的例子也有点棘手。发生这种情况是因为您很少 直接 使用这些引用,它们通常预先打包在实用程序中。例如,您可以 works (that directly uses the WeakReference and ReferenceQueue under the hood), or event . guava with its CacheBuilder used to offer some functionality dealing with SoftReferences(but not anymore), caffeine still does though.

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


就此而言,我们在生产中使用 WeakHashMap(我们也使用 Cleaner API,但更少)。如果你真的想了解它们,你需要了解 garbage collector 是如何工作的(比如,really 是如何工作的),然后阅读他们的官方文档并尝试(并询问)多个东西。