В чем разница между a.getClass () и A.class в Java?


102

Какие плюсы и минусы существуют в Java при выборе использования a.getClass()или A.class? Любой из них можно использовать везде, где Class<?>ожидается, но я предполагаю, что использование обоих в разных обстоятельствах принесет производительность или другие незначительные преимущества (как и в случае с Class.forName()и ClassLoader.loadClass().

Ответы:


163

Я бы не стал сравнивать их с точки зрения плюсов и минусов, так как у них разные цели, и редко бывает «выбор» между ними.

  • a.getClass()возвращает тип выполнения из a. Т.е. если есть A a = new B();то a.getClass()вернет Bкласс.

  • A.classоценивает Aкласс статически и используется для других целей, часто связанных с отражением.

Что касается производительности, разница может быть ощутимой, но я не буду ничего об этом говорить, потому что в конечном итоге она зависит от JVM и / или компилятора.


Это сообщение было переписано как статья здесь .


2
Как насчет A.class.getClass()?
user1870400

5
Это даст вам Classобъект класса, представляющий A.classобъект, который снова является экземпляром java.lang.Class.
aioobe

Как насчет A.getClass().class?
Shikhar Mainalee

@ShikharMainalee, это не имеет смысла, если Aэто класс. Для getClassклассов нет статического метода.
aioobe

как это связано с предложением здесь , что они также указывают на различные загрузчиков классов. Это также может быть существенная разница между ними?
Джим

32

На самом деле они разные в зависимости от того, где вы можете их использовать. A.classработает во время компиляции, в то время как a.getClass()требует экземпляра типа Aи работает во время выполнения.

Также может быть разница в производительности. Хотя A.classкомпилятор может разрешить его, поскольку он знает фактический тип A, a.getClass()это вызов виртуального метода, происходящий во время выполнения.

Для справки, целевой байт-код компилятора обычно выдает следующие инструкции для Integer.getClass():

aload_1
invokevirtual   #3; //Method java/lang/Object.getClass:()Ljava/lang/Class;

и следующее для Integer.class:

//const #3 = class  #16;    //  java/lang/Integer

ldc_w   #3; //class java/lang/Integer

Первый тип обычно включает отправку виртуального метода и, следовательно, предположительно занимает больше времени для выполнения. Однако это в конечном итоге зависит от JVM.


1
[1] технически Спецификация языка Java вообще не упоминает какой-либо постоянный пул ...
aioobe

@aioobe: Думаю, вы правы, поэтому я проверил байт-код, сгенерированный Sun JDK.
Tomasz Nurkiewicz

1
... который, с технической точки зрения, тоже не дает авторитетного ответа, поскольку в спецификации языка Java даже не упоминается байт-код, когда речь идет о семантике.
aioobe 08

@aioobe: Я понял вашу точку зрения. Я никогда не упоминал JLS, просто опытным путем проверил, как он работает, так как не был уверен. OP спрашивает о производительности, и проверка байт-кода показалась хорошей идеей. Не стесняйтесь редактировать мой пост или удалять неоднозначные высказывания
Томаш Нуркевич 08

1
откатывайся, если тебе не нравится ;-)
aioobe 08

8

взгляните на примеры ниже

a.getClass()!= A.class, т.е. a является не экземпляром A, а анонимным подклассом A

a.getClass() требуется экземпляр типа A


4

Используйте, a.getClassесли у вас есть экземпляр класса / типа и вы хотите получить его точный тип. while a.classиспользуется, когда у вас есть в typeналичии и вы хотите создать его экземпляр.
Также getClass()возвращает тип экземпляра во время выполнения, пока .classон оценивается во время компиляции.
Учитывая производительность getClass()и .class, .classимеет лучшую производительность, чем getClass() .
Пример :

public class PerfomanceClass {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        long time=System.nanoTime();
        Class class1="String".getClass();
        class1="String".getClass();
        class1="String".getClass();
        class1="String".getClass();

        System.out.println("time (getClass()) :"+(System.nanoTime()-time)+" ns");     


        long time2=System.nanoTime();
        Class class2=String.class;
        class2=String.class;
        class2=String.class;
        class2=String.class;

        System.out.println("time (.class):"+(System.nanoTime()-time2)+" ns");
    }

}

Вывод :

time (getClass()) : 79410 ns
time (.class)     : 8032 ns

1

Я хотел бы добавить одно отличие. Допустим, у вас есть класс конструктор, как показано ниже, с суперклассом, который принимает объект класса. Вы хотите, чтобы всякий раз, когда создается объект подкласса, объект класса подкласса должен передаваться суперклассу. Код ниже не будет компилироваться, так как вы не можете вызвать метод экземпляра в конструкторе. В том случае, если вы замените myObject.getClass()на MyClass.class. Он будет работать отлично.

Class MyClass
{
    private MyClass myObject = new MyClass();
    public MyClass()
    {
        super(myObject.getClass()); //error line compile time error
    }
}

2
Имея экземпляр того же класса, что и переменные экземпляра того же класса .... Вам не хватит места в куче, поскольку вы рекурсивно создаете объекты.
Аникет Такур

1

Интересно, что различия в производительности, упомянутые в приведенном выше примере, по-видимому, связаны с другими причинами. Используя 3 разных класса, в среднем производительность будет примерно одинаковой:

import java.util.LinkedHashMap;
public class PerfomanceClass {

public static void main(String[] args) {

    long time = System.nanoTime();
    Class class1 = "String".getClass();
    Class class11 = "Integer".getClass();
    Class class111 = "LinkedHashMap".getClass();

    System.out.println("time (getClass()) :" + (System.nanoTime() - time) + " ns");

    long time2 = System.nanoTime();
    Class class2 = String.class;
    Class class22 = Integer.class;
    Class class222 = LinkedHashMap.class;

    System.out.println("time (.class):" + (System.nanoTime() - time2) + " ns");
} }

Результат будет примерно таким:

time (getClass()) :23506 ns 
time (.class):23838 ns

А переключение порядка звонков даже getClass()ускорится.

import java.util.LinkedHashMap;

public class PerfomanceClass {

public static void main(String[] args) {
    long time2 = System.nanoTime();
    Class class2 = LinkedHashMap.class;

    System.out.println("time (.class):" + (System.nanoTime() - time2) + " ns");

    long time = System.nanoTime();
    Class class1 = "LinkedHashMap".getClass();

    System.out.println("time (getClass()) :" + (System.nanoTime() - time) + " ns");
}}

Вывод:

time (.class):33108 ns
time (getClass()) :6622 ns

«Использование 3 разных классов». Но в разделе getClass () вы не используете 3 разных класса. Все это String, поэтому getClass вернет java.lang.String для всех экземпляров.
Килиан

1

p.getClass(), где p- экземпляр объекта, возвращает класс среды выполнения этого объекта p. pне может быть типом, который вызовет ошибку времени компиляции, он должен быть экземпляром объекта.

// B extends A
A a = new B();
System.out.println(a.getClass());
//output: class B

p.classэто выражение. Это .classназывается синтаксисом класса. pэто тип. Это может быть имя класса, интерфейса или массива и даже примитивный тип. a.getClass() == B.class.

Если тип доступен и есть экземпляр, то можно использовать getClassметод для получения имени типа. В противном случае используйте .classсинтаксис

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.