繁体   English   中英

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

[英]Does .class property of an object always return the same instance?

我是否在以下代码中对同一对象实例进行同步? 我可以安全吗?

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");
    }
  }
}

根据JLS 8.4.3.6,Class.forName("name")进行同步,因此.class是正确的做法,并且至少在同一类中它可以工作。 此外,所有静态synchronized方法都在.class上同步。 就像在JLS中所说的,以下内容实际上是相同的:

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 12.2所述,不确定.class是何时由不同的类调用的,因为此调用取决于类加载器:

行为良好的类加载器保留以下属性:

给定相同的名称,好的类加载器应始终返回相同的类对象。

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

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

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

您必须在加载 Class解决 Class之间进行区分。

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

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

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


引用一些官方用语:

JVMSpec第5.3.2节。 使用用户定义的类加载器加载

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

JVMSpec第5.3.5节。 从类文件表示形式派生一个类

以下步骤用于使用加载程序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将询问定义的加载器。 或跳过要求它作为§当5.3.2状态Class对于给定的名称和装载机已经存在。

仅当它们具有相同的类加载器时。

如果您有一个根类加载器和两个子类加载器,则两个子类加载器(即URLClassLoader)每个类加载器都会加载一次.class,它们将异步工作。

根类加载器中的“加载Sync ”将被保存。

暂无
暂无

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

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