Яка різниця між a.getClass () та A.class у Java?


101

На 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()?
користувач1870400

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.
Томаш Нуркевич

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

@aioobe: Я розумію. Я ніколи не згадував JLS, просто емпірично перевіряв, як він працює, оскільки не був певен. ОП запитує про продуктивність та вивчення байт-коду здалося гарною ідеєю. Не соромтесь редагувати мою публікацію або видаляти неоднозначні заяви
Tomasz Nurkiewicz

1
відкатуйся, якщо тобі це не подобається ;-)
відкатуйся, aioobe

8

подивіться на приклади нижче

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

a.getClass() вимагає екземпляр типу A


4

Використовуйте, a.getClassколи у вас є примірник класу / типу, і ви хочете отримати точний його тип. в той час 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

Є одна різниця, яку я хотів би додати. Скажімо, у вас є клас конструктор, як показано нижче, із суперкласом, який приймає об’єкт Class. Ви хочете, щоб кожен раз, коли створено об'єкт підкласу, об’єкт класу підкласу повинен бути переданий суперкласу. Нижче код не буде компілюватися, оскільки ви не можете викликати метод екземпляра в конструкторі. У такому випадку, якщо ви заміните 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

Msgstr "Використання 3 різних класів". Але в розділі getClass () ви не використовуєте 3 різних класів. Це все String і тому getClass поверне java.lang.String для всіх примірників.
Кіліан

1

p.getClass(), де the 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.