简体   繁体   English

Java是否保证Object.getClass()== Object.getClass()?

[英]Does Java guarantee that Object.getClass() == Object.getClass()?

I really do mean identity-equality here. 我真的是在这里指身份平等。

For example, will the following always print true ? 例如,以下内容将始终打印true吗?

System.out.println("foo".getClass() == "fum".getClass());

Yes, class tokens are unique (for any given classloader, that is). 是的,类令牌是唯一的(对于任何给定的类加载器而言)。

Ie you will always get a reference to the same physical object within the same classloader realm . 即,您将始终在相同的类加载器领域中获得对相同物理对象的引用。 However, a different classloader will load a different class token, in conjunction with the fact that the same class definition is deemed different when loaded by two distinct classloaders. 但是,不同的类加载器将加载不同的类令牌,同时,当两个不同的类加载器加载相同的类定义时,该类定义也被视为不同。

See this earlier answer of mine for a demonstration of this. 有关示例,请参见我的较早答案

For two instances of class X , 对于X类的两个实例,

x1.getClass() == x2.getClass()

only if 除非

x1.getClass().getClassLoader() == x2.getClass().getClassLoader()

Note: Class.getClassLoader() may return null which implies the bootstrap ClassLoader. 注意: Class.getClassLoader()可能返回null,这意味着引导ClassLoader。

Yes. 是。

The returned Class object is the object that is locked by static synchronized methods of the represented class. 返回的Class对象是被表示的类的静态同步方法锁定的对象。

If it was possible to return multiple instances, then 如果可以返回多个实例,则

public static synchronized void doSomething() {..}

would not be thread-safe. 将不是线程安全的。

It is guaranteed per classloader, as stated in the JVM specification : JVM规范中所述,每个类加载器都可以保证它:

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. 首先,Java虚拟机确定是否已记录L是由N表示的类或接口的启动加载器。如果是,则此创建尝试无效,并且加载会引发LinkageError。

That is, if a class loader (L) tries to bypass default Class instances caching, and make the JVM load the byte[] definition more than once for the same class name (N), a LinkageError will be thrown by the JVM. 也就是说,如果类加载器(L)试图绕过默认的Class实例缓存,并且使JVM对于同一个类名(N)多次加载byte[]定义,则JVM将引发LinkageError

For example, implement a class loader that calls defineClass(...) each time loadClass(...) is invoked (bypassing default caching): 例如,实现一个每次调用loadClass(...)都会调用defineClass(...)的类加载器(绕过默认缓存):

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

and this is what happens: 这就是发生的情况:

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)

Cheers 干杯

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

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