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?


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
}

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


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.

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 ...


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.


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.


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)

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
}

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

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 []
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.