2012-06-08 13 views
87

W języku Java, jakie są zalety/wady dotyczące wyboru do korzystania z a.getClass() lub A.class? Albo może być stosowany wszędzie tam, gdzie oczekuje się Class<?>, ale mogę sobie wyobrazić, że nie będzie wydajność lub inne subtelne korzyści zarówno do korzystania w różnych okolicznościach (tak jak są z Class.forName() i ClassLoader.loadClass().Jaka jest różnica między a.getClass() i A.class w Javie?

Odpowiedz

138

Nie chciałbym porównać je pod względem plusy/minusy, ponieważ mają różne cele i nie rzadko jest „wybór”, aby między nimi.

  • a.getClass() zwraca typ Runtime z a tzn., jeśli masz A a = new B(); następnie a.getClass() zwróci B klasa.

  • A.class ocenia do klasy statycznieA i jest używany do innych celów często związanych z refleksji.

Pod względem wydajności, nie może być mierzalna różnica, ale nie powiem nic na ten temat, bo w końcu to jest JVM i/lub kompilator zależne.


Ten post został napisany od nowa jako artykuł here.

+0

Jak o 'A.class.getClass()'? – user1870400

+0

To da ci obiekt 'Class' klasy reprezentujący obiekt' A.class', który jest ponownie instancją 'java.lang.Class'. – aioobe

30

W rzeczywistości różnią się pod względem miejsca, w którym można z nich korzystać. A.class działa w czasie kompilacji, podczas gdy a.getClass() wymaga instancji typu A i działa w środowisku wykonawczym.

Może również występować różnica w wydajności. Podczas gdy A.class może być rozwiązany przez kompilator, ponieważ zna rzeczywisty typ A, a.getClass() jest wirtualnym wywołaniem metody zdarzającym się w środowisku wykonawczym.

Dla porównania, kompilator kierowania bajtowy zazwyczaj wydziela następujące instrukcje Integer.getClass():

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

i dodaje do Integer.class:

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

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

Były typowo obejmować wirtualne metody wysyłką i dlatego prawdopodobnie wykonanie dłuższego czasu. To jednak zależy od JVM.

+1

[1] technicznie specyfikacja języka Java nie wspomina żadnej puli stałej w ogóle ... – aioobe

+0

@aioobe: Zgaduję, że masz rację, dlatego sprawdziłem kod bajtowy wygenerowany przez Sun JDK. –

+1

... który technicznie rzecz biorąc nie zapewnia autorytatywnej odpowiedzi, ponieważ specyfikacja języka Java nawet nie wspomina o kodach bajtowych, jeśli chodzi o semantykę. – aioobe

5

spojrzeć na poniższych przykładach

a.getClass()!= A.class, czyli nie jest instancją ale anonimowego klasy sub A

a.getClass() wymaga instancję typu A

1

Nie jest jedna różnica, którą chciałbym dodać. Powiedzmy, że masz konstruktor klasy, jak pokazano poniżej, z super klasą, która przyjmuje obiekt klasy. Chcemy, aby po utworzeniu obiektu podklasy obiekt klasy subClass został przekazany do super klasy. Poniższy kod nie zostanie skompilowany, ponieważ nie można wywołać metody instancji w konstruktorze.W takim przypadku, jeśli zastąpisz myObject.getClass() z MyClass.class. Będzie działać idealnie.

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

Po wystąpieniu tej samej klasy, co zmienne instancji tej samej klasy .... Spowoduje to wyczerpanie przestrzeni sterty podczas rekurencyjnego tworzenia obiektów. –

4

Zastosowanie a.getClass kiedy trzeba instancję klasy/typu i chcesz uzyskać dokładny typ niego. podczas gdy a.class jest używany, gdy masz dostępną type i chcesz utworzyć jego instancję.
Również getClass() zwraca typ środowiska wykonawczego instancji, podczas gdy .class jest oceniany w czasie kompilacji.
Biorąc pod uwagę wydajność getClass() i .class, .class ma lepszą wydajność niż getClass().
przykład:

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

} 

wyjściowa:

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

interesujące różnice w wydajności wymienione w przykładzie powyżej, wydaje się być związana z innych powodów. Korzystanie z 3 różnych klas, w średnia wydajność będzie prawie taka sama:

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

wyjście będzie coś takiego:

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

i przełączanie kolejność połączeń nawet spowodować getClass() jest szybsza .

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

wyjściowa:

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

"Korzystanie z 3 różnych klas". Ale w sekcji getClass() nie używasz 3 różnych klas. Są to wszystkie String i dlatego getClass zwróci java.lang.String dla wszystkich instancji. – John

Powiązane problemy