Гарантирует ли Java, что Object.getClass() == Object.getClass()?

Я действительно имею в виду тождество-равенство здесь.

Например, всегда ли следующее будет выводить true?

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

person Mackenzie    schedule 17.09.2010    source источник
comment
Если класс (1) не переопределяет метод equals(Object); и (2) не является подклассом класса, который переопределяет метод equals(Object), тогда этот класс использует метод equals(Object), определенный в корневом классе Object, который использует оператор идентификации ==.   -  person emory    schedule 18.09.2010
comment
@emory: я думаю, что ваш комментарий неверен. == в этом фрагменте всегда выполняет сравнение ссылок, и оператор не может быть перегружен для вызова вместо него equals. Кроме того, java.lang.Class — это final, поэтому вы не можете переопределить его equals.   -  person polygenelubricants    schedule 18.09.2010


Ответы (4)


Да, токены класса уникальны (то есть для любого данного загрузчика классов).

т.е. вы всегда будете получать ссылку на один и тот же физический объект в одной и той же области загрузчика классов. Однако другой загрузчик классов загрузит другой токен класса в сочетании с тем фактом, что одно и то же определение класса считается различным при загрузке двумя разными загрузчиками классов.

См. этот мой более ранний ответ для демонстрации этого.

person Péter Török    schedule 17.09.2010

Для двух экземпляров класса X,

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

только если

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

Примечание. Class.getClassLoader() может возвращать значение null, что подразумевает загрузку ClassLoader.

person McDowell    schedule 18.09.2010
comment
Отличный способ выразить это - person slezica; 15.07.2014
comment
@McDowell, ваш последний абзац неверен. ClassLoader.getSystemClassLoader не совпадает с загрузчиком классов начальной загрузки. Если .getClassLoader() возвращает значение null, это означает, что класс загружается загрузчиком классов начальной загрузки. ClassLoader.getSystemClassLoader не вернет значение null. - person Pacerier; 29.08.2014

да.

Возвращенный объект класса — это объект, заблокированный статическими синхронизированными методами представляемого класса.

Если бы можно было вернуть несколько экземпляров, то

public static synchronized void doSomething() {..}

не будет потокобезопасным.

person Bozho    schedule 17.09.2010
comment
Еще одна подсказка заключается в том, что в javadoc говорится, что getClass возвращает объект класса The, который представляет класс среды выполнения этого объекта... а не объект класса A.... - person Stephen C; 18.09.2010

Это гарантировано для каждого загрузчика классов, как указано в спецификация JVM:

Во-первых, виртуальная машина Java определяет, записано ли уже, что L является инициирующим загрузчиком класса или интерфейса, обозначенного N. Если это так, эта попытка создания недействительна, и загрузка вызывает LinkageError.

То есть, если загрузчик классов (L) попытается обойти кэширование экземпляров Class по умолчанию и заставить JVM загружать определение byte[] более одного раза для одного и того же имени класса (N), 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)

Ваше здоровье

person idelvall    schedule 09.03.2016