我的确意味着身份平等。
例如,以下内容是否始终打印 true ?
System.out.println("foo".getClass() == "fum".getClass());
答案 0 :(得分:42)
是的,类标记是唯一的(对于任何给定的类加载器,即)。
即。您将始终在同一个类加载器领域中获得对同一物理对象的引用。但是,不同的类加载器将加载不同的类标记,并且当由两个不同的类加载器加载时,相同的类定义被认为是不同的。
请参阅this earlier answer of mine进行演示。
答案 1 :(得分:15)
对于类X
的两个实例,
x1.getClass() == x2.getClass()
仅限
x1.getClass().getClassLoader() == x2.getClass().getClassLoader()
注意:Class.getClassLoader()
可能会返回null,这意味着引导ClassLoader。
答案 2 :(得分:8)
是
返回的Class对象是由所表示的类的静态同步方法锁定的对象。
如果可以返回多个实例,那么
public static synchronized void doSomething() {..}
不会是线程安全的。
答案 3 :(得分:3)
每个类加载器都有保证,如JVM specification中所述:
首先,Java虚拟机确定它是否已经记录了L是由N表示的类或接口的初始加载器。如果是,则此创建尝试无效并且加载会引发LinkageError。
也就是说,如果类加载器(L)试图绕过默认的Class
实例缓存,并使JVM为同一个类名(N)多次加载byte[]
定义, JVM会抛出LinkageError
。
例如,实现一个每次调用defineClass(...)
时调用loadClass(...)
的类加载器(绕过默认缓存):
public class ClassloaderTest {
private static final byte[] CLASS_DEF = readClassBytes();
private static byte[] readClassBytes() {
try {
InputStream is = ClassloaderTest.class.getResourceAsStream("ClassloaderTest.class");
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[16384];
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
return buffer.toByteArray();
} catch (IOException ex) {
throw new AssertionError();
}
}
private static ClassLoader createNonCachingClassloader() {
return new ClassLoader() {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.equals("classloader.ClassloaderTest")) {
return defineClass(name, CLASS_DEF, 0, CLASS_DEF.length);
} else {
return getParent().loadClass(name);
}
}
};
}
public static void main(String[] args) throws Exception {
ClassLoader cl = createNonCachingClassloader();
Class<?> cl1 = cl.loadClass("classloader.ClassloaderTest");
Class<?> cl2 = cl.loadClass("classloader.ClassloaderTest");
System.out.println(cl1==cl2);
}
}
这就是发生的事情:
Exception in thread "main" java.lang.LinkageError: loader (instance of classloader/ClassloaderTest$1): attempted duplicate class definition for name: "classloader/ClassloaderTest"
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at classloader.ClassloaderTest$1.loadClass(ClassloaderTest.java:53)
at classloader.ClassloaderTest.main(ClassloaderTest.java:64)
干杯