Quelle est la différence entre a.getClass () et A.class en Java?

101

En Java, quels avantages / inconvénients existent autour du choix d'utiliser a.getClass()ou A.class? L'un ou l'autre peut être utilisé partout où un Class<?>est attendu, mais j'imagine qu'il y aurait des performances ou d'autres avantages subtils à utiliser les deux dans des circonstances différentes (tout comme il y en a avec Class.forName()et ClassLoader.loadClass().

IAmYourFaja
la source

Réponses:

163

Je ne les comparerais pas en termes de pour / contre car ils ont des objectifs différents et il y a rarement un "choix" à faire entre les deux.

  • a.getClass()renvoie le type d'exécution de a. Ie, si vous avez A a = new B();alors a.getClass()retournera la Bclasse.

  • A.classévalue à la Aclasse de manière statique , et est utilisé à d'autres fins souvent liées à la réflexion.

En termes de performances, il peut y avoir une différence mesurable, mais je ne dirai rien à ce sujet car au final, il dépend de la JVM et / ou du compilateur.


Cet article a été réécrit sous forme d'article ici .

aioobe
la source
2
Et pourquoi pas A.class.getClass()?
user1870400
5
Cela vous donnerait l' Classobjet de la classe représentant l' A.classobjet qui est à nouveau une instance de java.lang.Class.
aioobe
Et pourquoi pas A.getClass().class?
Shikhar Mainalee
@ShikharMainalee, cela n'a pas vraiment de sens si Ac'est une classe. Il n'y a pas de getClassméthode statique sur les classes.
aioobe
comment cela se rapporte-t-il à la suggestion ici qu'ils pointent également vers différents chargeurs de classe. Cela pourrait également être une différence significative entre les deux?
Jim
32

Ils sont en fait différents en ce qui concerne les endroits où vous pouvez les utiliser. A.classfonctionne au moment de la compilation alors qu'il a.getClass()nécessite une instance de type Aet fonctionne au moment de l'exécution.

Il peut également y avoir une différence de performance. Alors que A.classpeut être résolu par le compilateur car il connaît le type réel de A, a.getClass()un appel de méthode virtuelle se produit au moment de l'exécution.

Pour référence, un compilateur ciblant le bytecode émet généralement les instructions suivantes pour Integer.getClass():

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

et ce qui suit pour Integer.class:

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

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

Le premier impliquerait généralement une distribution de méthode virtuelle et prendrait donc vraisemblablement plus de temps à s'exécuter. Cela dépend cependant de la JVM.

Tomasz Nurkiewicz
la source
1
[1] techniquement, la spécification du langage Java ne mentionne aucun pool constant ...
aioobe
@aioobe: Je suppose que vous avez raison, c'est pourquoi j'ai vérifié le bytecode généré par Sun JDK.
Tomasz Nurkiewicz
1
... qui, techniquement parlant, ne fournit pas non plus de réponse faisant autorité, puisque la spécification du langage Java ne mentionne même pas le bytecode en matière de sémantique.
aioobe
@aioobe: Je comprends votre point. Je n'ai jamais mentionné JLS, j'ai juste vérifié empiriquement son fonctionnement, car je n'étais pas sûr. L'OP pose des questions sur les performances et l'examen du bytecode semble être une bonne idée. N'hésitez pas à modifier mon message ou à supprimer les déclarations ambiguës
Tomasz Nurkiewicz
1
revenir en arrière si vous ne l'aimez pas ;-)
aioobe
8

jetez un œil aux exemples ci-dessous

a.getClass()!= A.class, ie a n'est pas une instance de A mais d'une sous-classe anonyme de A

a.getClass() nécessite une instance de type A

Massimiliano Peluso
la source
4

À utiliser a.getClasslorsque vous avez une instance de classe / type et que vous souhaitez en obtenir le type exact. while a.classest utilisé lorsque vous en disposez typeet que vous souhaitez en créer une instance.
Renvoie également le getClass()type d'exécution de l'instance pendant qu'elle .classest évaluée au moment de la compilation.
Compte tenu des performances de getClass()et .class, .classa de meilleures performances que getClass() .
Exemple :

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

}

Production :

time (getClass()) : 79410 ns
time (.class)     : 8032 ns
Rohan
la source
1

Il y a une différence que je voudrais ajouter. Supposons que vous ayez une classe un constructeur comme indiqué ci-dessous avec une super classe qui prend un objet Class. Vous voulez que chaque fois qu'un objet de sous-classe est créé, l'objet de classe de la sous-classe soit passé à la super-classe. Le code ci-dessous ne sera pas compilé car vous ne pouvez pas appeler une méthode d'instance dans un constructeur. Dans ce cas, si vous remplacez myObject.getClass()par MyClass.class. Cela fonctionnera parfaitement.

Class MyClass
{
    private MyClass myObject = new MyClass();
    public MyClass()
    {
        super(myObject.getClass()); //error line compile time error
    }
}
prashant
la source
2
Avoir une instance de la même classe comme variables d'instance de la même classe .... Vous manquerez d'espace de tas lorsque vous créez des objets de manière récursive.
Aniket Thakur
1

Il est intéressant de noter que les différences de performance mentionnées dans l'exemple ci-dessus semblent être liées à d'autres raisons. En utilisant 3 classes différentes, en moyenne, les performances seront presque les mêmes:

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

La sortie sera quelque chose comme:

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

Et changer l'ordre des appels vous permettra même d' getClass()être plus rapide.

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

Production:

time (.class):33108 ns
time (getClass()) :6622 ns
user4287932
la source
"Utilisation de 3 classes différentes". Mais dans la section getClass (), vous n'utilisez pas 3 classes différentes. Ce sont tous des String et donc getClass retournera java.lang.String pour toutes les instances.
Kilian
1

p.getClass(), où pest une instance d'un objet, renvoie la classe d'exécution de cet objet p. pne peut pas être un type qui provoquera une erreur de compilation, il doit s'agir d'une instance d'un objet.

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

p.classest une expression. Le .classs'appelle la syntaxe de classe. pest un type. Cela peut être le nom d'une classe, d'une interface ou d'un tableau et même d'un type primitif. a.getClass() == B.class.

Si un type est disponible et qu'il existe une instance, il est possible d'utiliser la getClassméthode pour obtenir le nom du type. Sinon, utilisez la .classsyntaxe

triple pierre
la source