对象的.class属性总是返回相同的实例吗? [英] Does .class property of an object always return the same instance?
问题描述
我在下面的代码中在同一对象实例上同步?我可以安全吗?
Class Sync {}
A类实现Runnable {
void run(){
synchronized(Sync.class){
System.out.println(I am synchronized);
}
}
}
B类实现Runnable {
void run(){
synchronized(Sync.class){
System.out.println(I too am synchronize);
}
}
}
您必须区分类
的加载和 > 类 c
ClassLoader.loadClass(...)
。而 ClassLoader
可能以奇怪的方式实现后者,例如。通过在每次调用时返回不同的实例,JVM将根据上下文每次解析每个类,并记住结果。 重要的是, 如果符号引用的分辨率可以重定向, static final
变量也不会有帮助。如果在JVM中有两个相同的 Class
实例,它们的 static final
字段会有两个不同的版本
在 Class
实例和每个类数据的JVM之间存在一个一对一的映射。
列举几个官方词汇:
JVMSpec§ 5.3.2。使用用户定义的类加载器加载
...首先,Java虚拟机确定L是否已被记录为类或接口的初始加载器表示为N.如果是,这个类或接口是C,并且不需要创建类。
...
...
JVMSpec§5.3.5。从类派生类文件表示
以下步骤用于为nonarray类或接口C派生一个Class对象,使用loader L
(1)首先,Java虚拟机确定它是否已经记录了L是类或接口的初始加载器如果是,则此创建尝试无效,并且加载会抛出LinkageError。
...
5)Java虚拟机将C标记为具有L作为其定义类加载器,并记录L是C的启动加载器(§5.3.4)。
§5.3.5指出的重要一点是每个 ClassLoader
可以每个唯一的符号定义最多一个类名称。它可能通过委托给不同的装载器返回不同的实例,但是它们将被记住为定义装载器。当解析从 Class
到另一个 Class
的引用时,JVM会询问 。或者跳过请求它作为§5.3.2状态,当给定的名称和加载程序已经存在 Class
时。
Am I synchronizing on the same object instance in the following code? Can I do it safely?
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");
}
}
}
You have to make a distinction between Loading of a Class
and Resolving a Class
.
Class literals and the special method Class.forName(…)
are different than the method ClassLoader.loadClass(…)
. While a ClassLoader
might implement the latter in strange ways, e.g. by returning different instances on each call, the JVM will resolve each class exactly once per context and remember the result.
The important point is, if the resolution of a symbolic reference could be redirected, a static final
variable would not help either. If you have two instances of the same Class
in your JVM, two different version of their static final
fields would exist as well.
There is a one-by-one mapping between a Class
instance and the JVM per class data.
To cite a few official words:
JVMSpec § 5.3.2. Loading Using a User-defined Class Loader
… First, the Java Virtual Machine determines whether L has already been recorded as an initiating loader of a class or interface denoted by N. If so, this class or interface is C, and no class creation is necessary. …
…
JVMSpec § 5.3.5. Deriving a Class from a class File Representation
The following steps are used to derive a Class object for the nonarray class or interface C denoted by N using loader L from a purported representation in class file format.
(1) First, the Java Virtual Machine determines whether it has already recorded that L is an initiating loader of a class or interface denoted by N. If so, this creation attempt is invalid and loading throws a LinkageError.
…
(5) The Java Virtual Machine marks C as having L as its defining class loader and records that L is an initiating loader of C (§5.3.4).
The important point as pointed out by § 5.3.5 is that each ClassLoader
can define at most one class per unique symbolic name. It might return different instances by delegating to different loaders but then they would be remembered as the defining loader. And the JVM will ask the defining loader when resolving references from a Class
to another Class
. Or skip asking it as § 5.3.2 states when a Class
for a given name and loader already exists.
这篇关于对象的.class属性总是返回相同的实例吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!