Comment déterminer la classe d'un objet?

510

Si la classe Bet la classe Cétendent la classe Aet que j'ai un objet de type Bou C, comment puis-je déterminer de quel type il s'agit d'une instance?

transporteur
la source
14
@starblue Casting serait la première chose qui me vient à l'esprit. Je doute que l' opérateur instanceof existerait s'il n'y en avait pas besoin.
b1nary.atr0phy
@ b1nary.atr0phy ne serait-il pas bon d'utiliser d'abord l'opérateur isntanceof. S'il y a un casting à un type incompatible, je pense que cela va entraîner une ClassCastException
committedandroider

Réponses:

801
if (obj instanceof C) {
//your code
}
IAdapter
la source
31
Il est utile de noter la vérification inverse ou comment vérifier si un objet n'est PAS une instance d'une classe:if(!(obj instanceof C))
Dzhuneyt
32
Je crois que la méthode getClass () est la réponse à la question d'origine. Dans ce cas (obj instanceof A) donnerait également une sortie "vraie" mais l'intention est de trouver la classe d'exécution de l'objet dans l'image. Si Parent1 est étendu par Child1 et Child2, essayez le code Child1 suivant child1 = new Child1 (); Parent1 parentChild = new Child2 (); Child2 child2 = nouveau Child2 (); (instance child1 de Parent1); (instance child1 de Child1); (instance parentChild de Child2); (instance parentChild de Parent1); (instance parentChild de Child1); code , il peut effacer l'intention d'instanceof.
Bhavesh Agarwal
Certainement une alternative à la construction d'une interface
JohnMerlino
3
Et si j'ai deux classes implémentant une seule interface? Comment distinguer la classe exacte de l'objet?
olyv
3
Une chose cependant, cela ne fonctionne pas si obj est nul. La solution serait alors ParentInterface.class.isAssignableFrom (Child.class)
alexbt
351

Utilisez Object.getClass () . Il renvoie le type d'exécution de l'objet.

Bill le lézard
la source
12
C'est en fait ainsi que vous déterminez la classe d'un objet
AA_PV
impeccable réponse @ Bill
Gaurav
1
Je ne sais pas pourquoi ce n'est pas la réponse la plus populaire
eicksl
178

Plusieurs bonnes réponses ont été présentées, mais il existe encore plus de méthodes: Class.isAssignableFrom()et simplement essayer de lancer l'objet (ce qui pourrait jeter un ClassCastException).

Résumés possibles

Résumons les différentes manières de tester si un objet objest une instance de type C:

// Method #1
if (obj instanceof C)
    ;

// Method #2
if (C.class.isInstance(obj))
    ;

// Method #3
if (C.class.isAssignableFrom(obj.getClass()))
    ;

// Method #4
try {
    C c = (C) obj;
    // No exception: obj is of type C or IT MIGHT BE NULL!
} catch (ClassCastException e) {
}

// Method #5
try {
    C c = C.class.cast(obj);
    // No exception: obj is of type C or IT MIGHT BE NULL!
} catch (ClassCastException e) {
}

Différences de nullmanipulation

Il existe cependant une différence de nullmanipulation:

  • Dans les 2 premières méthodes, les expressions évaluent falsesi objest null( nulln'est pas une instance de quoi que ce soit).
  • La 3ème méthode lancerait NullPointerExceptionévidemment.
  • Les 4ème et 5ème méthodes acceptent au contraire nullcar nullpeuvent être castées sur n'importe quel type!

À retenir: null n'est pas une instance de n'importe quel type mais elle peut être convertie en n'importe quel type.

Remarques

  • Class.getName()ne doit pas être utilisé pour effectuer un test "is-instance-of" car si l'objet n'est pas de type Cmais une sous-classe de celui-ci, il peut avoir un nom et un package complètement différents (donc les noms de classe ne correspondront évidemment pas) mais il est toujours de type C.
  • Pour la même raison d'héritage Class.isAssignableFrom()n'est pas symétrique :
    obj.getClass().isAssignableFrom(C.class)retournerait falsesi le type de objest une sous-classe de C.
icza
la source
6
Ceci est un très bon résumé de nombreux pièges dans les différentes méthodes. Merci pour cette écriture complète!
Kelsin
32

Vous pouvez utiliser:

Object instance = new SomeClass();
instance.getClass().getName(); //will return the name (as String) (== "SomeClass")
instance.getClass(); //will return the SomeClass' Class object

HTH. Mais je pense que la plupart du temps, ce n'est pas une bonne pratique de l'utiliser pour contrôler le flux ou quelque chose de similaire ...

Johannes Weiss
la source
Je l'ai utilisé pour créer un enregistreur générique, j'ai donc envoyé un objet à l'enregistreur, et il se connecte en fonction du nom de classe de l'objet, plutôt que de donner une balise de journal ou une chaîne de journal à chaque fois. merci
MBH
24

Toute utilisation de l'une des méthodes suggérées est considérée comme une odeur de code basée sur une mauvaise conception OO.

Si votre design est bon, vous ne devriez pas avoir à utiliser getClass()ou instanceof.

N'importe laquelle des méthodes suggérées fera l'affaire, mais juste quelque chose à garder à l'esprit, au niveau de la conception.

Yuval Adam
la source
3
Oui, probablement 99% des utilisations de getClass et instanceof peuvent être évitées avec des appels de méthodes polymorphes.
Bill the Lizard
3
Je suis d'accord. dans ce cas, je travaille avec des objets générés à partir de xml suivant un schéma mal conçu dont je n'ai pas la propriété.
transporteur
28
Pas nécessairement. Parfois, la séparation des interfaces est bonne. Il y a des moments où vous voulez savoir si A est un B, mais vous ne voulez pas rendre obligatoire que A est un B, car seul A est requis pour la plupart des fonctionnalités - B a une fonctionnalité facultative.
MetroidFan2002
8
En outre, il y a des moments où vous devez vous assurer que l'objet est de la même classe avec laquelle vous comparez; par exemple, j'aime remplacer la méthode equals de Object lorsque je crée ma propre classe. Je vérifie toujours que l'objet entrant est de la même classe.
StackOverflowed
58
De plus, je dirais que dire aux gens que quelque chose est mauvais sans expliquer exactement pourquoi ou donner une référence à un document, un livre ou toute autre ressource où le problème est expliqué n'est pas considéré comme constructif. Par conséquent et sachant que je suis dans StackOverflow, je ne sais pas pourquoi les gens ont tant voté pour cette réponse. Quelque chose change ici ...
Adrián Pérez
15

Nous pouvons utiliser la réflexion dans ce cas

objectName.getClass().getName();

Exemple:-

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    String name = request.getClass().getName();
}

Dans ce cas, vous obtiendrez le nom de la classe que l'objet passera à la HttpServletRequestvariable de référence d'interface.

user1884500
la source
c'est correct. utiliser uniquement obj.getClass()renverra le nom de classe, préfixe par le motclass
x6iae
request.getClass().getName();imprime tout le paquet! avec le nom de la classe
shareef
13

Il existe également une .isInstanceméthode sur la Classclasse " ". si vous obtenez la classe d'un objet via, myBanana.getClass()vous pouvez voir si votre objet myAppleest une instance de la même classe que myBananavia

myBanana.getClass().isInstance(myApple)
Andreas Petersson
la source
1

vérifier avec isinstance()ne serait pas suffisant si vous voulez savoir en temps d'exécution. utilisation:

if(someObject.getClass().equals(C.class){
    // do something
}
Alon Gouldman
la source
0

J'utilise la fonction Blow dans ma classe GeneralUtils, vérifiez qu'elle peut être utile

    public String getFieldType(Object o) {
    if (o == null) {
        return "Unable to identify the class name";
    }
    return o.getClass().getName();
}
Ahmed Salem
la source
0

J'ai utilisé des génériques Java 8 pour obtenir l'instance d'objet au moment de l'exécution plutôt que d'avoir à utiliser un commutateur

 public <T> void print(T data) {
    System.out.println(data.getClass().getName()+" => The data is " + data);
}

passez n'importe quel type de données et la méthode imprimera le type de données que vous avez passé lors de son appel. par exemple

    String str = "Hello World";
    int number = 10;
    double decimal = 10.0;
    float f = 10F;
    long l = 10L;
    List list = new ArrayList();
    print(str);
    print(number);
    print(decimal);
    print(f);
    print(l);
    print(list);

Voici la sortie

java.lang.String => The data is Hello World
java.lang.Integer => The data is 10
java.lang.Double => The data is 10.0
java.lang.Float => The data is 10.0
java.lang.Long => The data is 10
java.util.ArrayList => The data is []
Saurabh Verma
la source