简体   繁体   English

Java Class 实例是 singleton 吗?

[英]Is a Java Class instance singleton?

According to the Java 8 Language Spec §15.8.2 (quote):根据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. 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.

[...] [...]

Mainly, 'the Class object' insinuates that this is or should be a singleton.主要是,“ Class对象”暗示这是或应该是 singleton。 Also §12.2 says: §12.2 还说:

[...] [...]

Well-behaved class loaders maintain these properties:表现良好的 class 加载程序保持以下属性:

  • Given the same name, a good class loader should always return the same class object.给定相同的名称,一个好的 class 加载程序应该总是返回相同的 class object。

[...] [...]

In fact, using Java 8*, the following** prints true and true :事实上,使用 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());
    }
}

Is the class loader always 'well-behaved' and why (not)? class 装载机是否总是“表现良好”,为什么(不)? In other words: are Class instances singleton?换句话说: Class实例是 singleton 吗? The other way around: can a Class of the same type be a different instance?反过来:同一类型的Class可以是不同的实例吗?

Notes: I do not refer to the singleton pattern here.注意:我这里没有提到 singleton 模式。 However, if the Class implementation follows that pattern, that would be interesting.但是,如果Class实现遵循该模式,那将会很有趣。 As a side-step, but by no means the main question: because the singleton pattern's legitimate uses are point of debate, would Java's Class be a good candidate to apply the singleton pattern to?作为一个次要步骤,但绝不是主要问题:因为 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)

**: my IDE even warns me that the printed expressions are always true . **:我的 IDE 甚至警告我打印的表达式总是true

You are using the term singleton incorrectly.您错误地使用了术语singleton

A singleton implies the existence of only one object of its own class.一个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. 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 the runtime. 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运行时。

Your example is not capable of spotting whether the class loader is well behaved or not.您的示例无法发现 class 加载程序是否表现良好。 You already mentioned JLS §12.2您已经提到了JLS §12.2

Well-behaved class loaders maintain these properties:表现良好的 class 加载程序保持以下属性:

  • Given the same name, a good class loader should always return the same class object.给定相同的名称,一个好的 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. 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.

A malicious class loader could violate these properties.恶意 class 加载程序可能会违反这些属性。 However, it could not undermine the security of the type system, because the Java Virtual Machine guards against this.但是,它不会破坏类型系统的安全性,因为 Java 虚拟机可以防止这种情况发生。

Mind the last sentence.注意最后一句话。 A JVM will guard against violations of these requirements. JVM 将防止违反这些要求。 With the repeated occurrences of the same symbolic references within your example code, there are two possibilities在您的示例代码中重复出现相同的符号引用,有两种可能性

  1. The JVM remembers the result of the first resolution of this symbolic reference within this context and just reuses it on the next occurrence without asking a class loader again. JVM 在此上下文中记住此符号引用的第一次解析的结果,并在下一次出现时重复使用它,而无需再次询问 class 加载程序。

  2. The JVM remembers the result of the first resolution of this symbolic reference within this context and compares it with the result of subsequent resolutions of the same reference and throws an error if they mismatch. JVM 记住此上下文中此符号引用的第一次解析的结果,并将其与同一引用的后续解析的结果进行比较,如果它们不匹配,则会引发错误。

Since both approaches imply remembering the result, the first approach is usually used when it comes to resolving the same reference within the same context, as it is simpler and more efficient.由于这两种方法都意味着记住结果,因此当涉及在相同上下文中解析相同引用时,通常使用第一种方法,因为它更简单且更有效。 When it comes to different symbolic references that resolve to classes using the same reference, the JVM will indeed throw an error when the class loader constraints are violated .当涉及使用相同引用解析为类的不同符号引用时,JVM 确实会在 class 加载程序约束被违反时抛出错误

So expressions like Main.class == Main.class or new Main().getClass() == new Main().getClass() will never evaluate to false .所以像Main.class == Main.classnew Main().getClass() == new Main().getClass()这样的表达式永远不会计算为false Most likely, the resolution of the symbolic reference to Main will go a short-cut, using the same runtime class regardless of what the class loader would do.最有可能的是,对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. 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. In neither case could it result in false .在这两种情况下都不会导致false

In a single classloader, the Class object is the same.在单个类加载器中, Class object 是相同的。

Is the class loader always 'well-behaved' and why (not)? class 装载机是否总是“表现良好”,为什么(不)?

It really depends on the implementation.这真的取决于实施。 If it is done deliberately that always the classloader always returns a new Class -Object, it won't be well-behaved.如果故意让类加载器总是返回一个新的Class -Object,它不会表现得很好。 At least all classloaders of OpenJDK are well-behaving.至少 OpenJDK 的所有类加载器都表现良好。

In other words: are Class instances singleton?换句话说:Class 实例是 singleton 吗? The other way around: can a Class of the same type be a different instance?反过来:同一类型的 Class 可以是不同的实例吗?

In one single classloader, every Class instance is a singleton.在一个类加载器中,每个 Class 实例都是 singleton。 With multiple classloaders, following will evaluate to false:使用多个类加载器,以下将评估为 false:

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

The other way around: can a Class of the same type be a different instance?反过来:同一类型的 Class 可以是不同的实例吗?

Only if loaded by two different, conforming,well-behaved classloaders.仅当由两个不同的、一致的、行为良好的类加载器加载时。

As a side-step, but by no means the main question: because the singleton pattern's legitimate uses are point of debate, would Java's Class be a good candidate to apply the singleton pattern to?作为一个次要步骤,但绝不是主要问题:因为 singleton 模式的合法用途是争论的焦点,Java 的 Class 是否适合将 Z2ED500A3529637175E675A8791B7C6 模式应用于?

This is quite opinion-based, but I think, it's no good candidate to apply the singleton pattern, as most singletons are implemented like this:这是相当基于意见的,但我认为,它不是应用 singleton 模式的好选择,因为大多数单例都是这样实现的:

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

So more that it is really ONE object of a Class, many that only differ by some small things like a different Classloader.更重要的是,它实际上是 Class 中的一个 object,许多只是在一些小事情上有所不同,例如不同的 Classloader。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM