簡體   English   中英

Java Class 實例是 singleton 嗎?

[英]Is a Java Class instance singleton?

根據Java 8 語言規范§15.8.2 (引用):

[...]

A class literal evaluates to the Class object for the named type (or for void) as defined by the defining class loader ( §12.2 ) of the class of the current instance.

[...]

主要是,“ Class對象”暗示這是或應該是 singleton。 §12.2 還說:

[...]

表現良好的 class 加載程序保持以下屬性:

  • 給定相同的名稱,一個好的 class 加載程序應該總是返回相同的 class object。

[...]

事實上,使用 Java 8*,以下**打印truetrue

class Main {
    public static void main(String[] args) {
        Main main1 = new Main();
        Main main2 = new Main();
        System.out.println(main1.getClass().equals(main2.getClass()));
        System.out.println(main1.getClass() == main2.getClass());
    }
}

class 裝載機是否總是“表現良好”,為什么(不)? 換句話說: Class實例是 singleton 嗎? 反過來:同一類型的Class可以是不同的實例嗎?

注意:我這里沒有提到 singleton 模式。 但是,如果Class實現遵循該模式,那將會很有趣。 作為一個次要步驟,但絕不是主要問題:因為 singleton 模式的合法用途是爭論的焦點,Java 的Class是否適合將 Z2ED500A3529637175E675A8791B7C6 模式應用於?

*:

$ java -version
openjdk version "1.8.0_262"
OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_262-b10)
OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.262-b10, mixed mode)

**:我的 IDE 甚至警告我打印的表達式總是true

您錯誤地使用了術語singleton

一個singleton意味着它自己的 class 中只存在一個 object。 A Class object is an instance of the class java.lang.Class and there is more than one instance of this class. It's actually impossible to have only one Class object, as the existence of a Class object does already imply the existence of at least two classes, java.lang.Object and java.lang.Class , so there must be at least two Class objects in運行時。

您的示例無法發現 class 加載程序是否表現良好。 您已經提到了JLS §12.2

表現良好的 class 加載程序保持以下屬性:

  • 給定相同的名稱,一個好的 class 加載程序應該總是返回相同的 class object。

  • If a class loader L1 delegates loading of a class C to another loader L2 , then for any type T that occurs as the direct superclass or a direct superinterface of C , or as the type of a field in C , or as the type of a formal parameter of a method or constructor in C , or as a return type of a method in C , L1 and L2 should return the same Class object.

惡意 class 加載程序可能會違反這些屬性。 但是,它不會破壞類型系統的安全性,因為 Java 虛擬機可以防止這種情況發生。

注意最后一句話。 JVM 將防止違反這些要求。 在您的示例代碼中重復出現相同的符號引用,有兩種可能性

  1. JVM 在此上下文中記住此符號引用的第一次解析的結果,並在下一次出現時重復使用它,而無需再次詢問 class 加載程序。

  2. JVM 記住此上下文中此符號引用的第一次解析的結果,並將其與同一引用的后續解析的結果進行比較,如果它們不匹配,則會引發錯誤。

由於這兩種方法都意味着記住結果,因此當涉及在相同上下文中解析相同引用時,通常使用第一種方法,因為它更簡單且更有效。 當涉及使用相同引用解析為類的不同符號引用時,JVM 確實會在 class 加載程序約束被違反時拋出錯誤

所以像Main.class == Main.classnew Main().getClass() == new Main().getClass()這樣的表達式永遠不會計算為false 最有可能的是,對Main的符號引用的解析將 go 成為一條捷徑,使用相同的運行時 class 而不管 class 加載程序會做什么。 But even when it does not take the short-cut and the ClassLoader is misbehaving, returning a different class object for the next query, the JVM would detect it and throw an error, so the expression would not evaluate to a boolean result at all. 在這兩種情況下都不會導致false

在單個類加載器中, Class object 是相同的。

class 裝載機是否總是“表現良好”,為什么(不)?

這真的取決於實施。 如果故意讓類加載器總是返回一個新的Class -Object,它不會表現得很好。 至少 OpenJDK 的所有類加載器都表現良好。

換句話說:Class 實例是 singleton 嗎? 反過來:同一類型的 Class 可以是不同的實例嗎?

在一個類加載器中,每個 Class 實例都是 singleton。 使用多個類加載器,以下將評估為 false:

ClassLoaderA.getInstance().loadClass("foo.Bar")==ClassLoaderB.getInstance().loadClass("foo.Bar");

反過來:同一類型的 Class 可以是不同的實例嗎?

僅當由兩個不同的、一致的、行為良好的類加載器加載時。

作為一個次要步驟,但絕不是主要問題:因為 singleton 模式的合法用途是爭論的焦點,Java 的 Class 是否適合將 Z2ED500A3529637175E675A8791B7C6 模式應用於?

這是相當基於意見的,但我認為,它不是應用 singleton 模式的好選擇,因為大多數單例都是這樣實現的:

class Foo{
   public static final Foo INSTANCE=new Foo();
   private Foo(){
      ìf(INSTANCE!=null)
         throw new IllegalAccessException("No Foo instances for you!");
   }
}

更重要的是,它實際上是 Class 中的一個 object,許多只是在一些小事情上有所不同,例如不同的 Classloader。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM