对象的.class属性是否始终返回相同的实例?

时间:2014-05-05 13:41:23

标签: java class singleton

我是否在以下代码中同步对象实例?我可以安全地做到吗?

Class Sync {}

Class A implements Runnable {
  void run() {
    synchronized(Sync.class) {
      System.out.println("I am synchronized");
    }
  }
}

Class B implements Runnable {
  void run() {
    synchronized(Sync.class) {
      System.out.println("I too am synchronized");
    }
  }
}

3 个答案:

答案 0 :(得分:3)

根据Class.forName("name")同步.class,因此,synchronized是正确的事情,它将起作用 - 至少在同一个班级。此外,所有静态.class方法都在class Test { int count; synchronized void bump() { count++; } static int classCount; static synchronized void classBump() { classCount++; } } class Test { int count; void bump() { synchronized (this) { count++; } } static int classCount; static void classBump() { try { synchronized (Class.forName("Test")) { classCount++; } } catch (ClassNotFoundException e) {} } } 上同步。正如它在JLS中所说,以下几乎是相同的:

.class

但是,正如JLS 8.4.3.6所述,不确定何时由不同的类调用{{1}},因为此调用依赖于类加载器:

  

表现良好的类加载器维护这些属性:

     

给定相同的名称,一个好的类加载器应该总是返回相同的类对象。

     

如果类加载器L1将类C的加载委托给另一个加载器L2,那么对于作为直接超类或者超类的任何类型T   C的直接超接口,或C中的字段类型,或者   C中方法或构造函数的形式参数的类型,或者   C,L1和L2中的方法的返回类型应该返回相同的类   对象

     

恶意类加载器可能违反这些属性。但是,它不能破坏类型系统的安全性,因为Java虚拟机可以防范这种情况。

因此,如果您使用标准Java类加载器 - 您应该没问题。但是,如果您使用的是某些自定义类加载器,则应注意错误。

答案 1 :(得分:1)

您必须区分{em>正在加载 Class解析 a Class

类文字和特殊方法Class.forName(…)与方法ClassLoader.loadClass(…)不同。虽然ClassLoader可能会以奇怪的方式实现后者,例如通过在每次调用时返回不同的实例,JVM将每个上下文解析每个类一次,并记住结果。

重要的是,如果符号引用的分辨率可以重定向,static final变量也无济于事。如果JVM中有两个相同Class的实例,则它们的static final字段也会存在两个不同版本。

Class实例与每个类数据的JVM之间存在一对一的映射。


引用一些官方词语:

  

JVMSpec § 5.3.2. Loading Using a User-defined Class Loader

     

...首先,Java虚拟机确定L是否已被记录为由N表示的类或接口的初始加载器。如果是,则此类或接口是C,并且不需要创建类。   ...

     

...

     

JVMSpec § 5.3.5. Deriving a Class from a class File Representation

     

以下步骤用于使用加载器L从类文件格式的声称表示中派生N表示的非阵列类或接口C的Class对象。

     

(1)首先,Java虚拟机确定它是否已经记录了L是由N表示的类或接口的启动加载器。如果是,则此创建尝试无效并且加载会引发LinkageError。

     

...

     

(5)Java虚拟机将C标记为L作为其定义的类加载器,并记录L是C的初始加载器(§5.3.4)。

第5.3.5节指出的重点是每个ClassLoader每个唯一的符号名称最多可以定义一个类。它可能通过委托给不同的加载器返回不同的实例,但随后它们将被记住为定义加载器。在解析从Class到另一个Class的引用时,JVM将询问定义加载器。或者,当给定名称和加载器的Class已经存在时,请跳过将其视为§5.3.2状态。

答案 2 :(得分:0)

只有他们有相同的类加载器。

如果你有一个root-classloader和两个child-class-loader,那么两个child-class-loader(即URLClassLoader)每个类加载器加载一次.class,它们将工作异步。

在root-classloader中加载Sync将保存。