繁体   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