Wie bestimme ich die Klasse eines Objekts?


510

Wenn Klasse Bund Klasse Klasse Cerweitern Aund ich ein Objekt vom Typ Boder habe C, wie kann ich feststellen, von welchem ​​Typ es sich um eine Instanz handelt?


14
@starblue Casting wäre das erste, was mir in den Sinn kommt. Ich bezweifle, dass die Instanz des Operators existieren würde, wenn sie nicht benötigt würde.
b1nary.atr0phy

@ b1nary.atr0phy wäre es nicht gut, zuerst den Operator isntanceof zu verwenden. Wenn es eine Umwandlung in einen nicht kompatiblen Typ, glaube ich , dass in einer Classcast führen
committedandroider

Antworten:


801
if (obj instanceof C) {
//your code
}

31
Es ist nützlich, die umgekehrte Prüfung zu beachten oder zu prüfen, ob ein Objekt KEINE Instanz einer Klasse ist:if(!(obj instanceof C))
Dzhuneyt

32
Ich glaube, die Methode getClass () ist die Antwort auf die ursprüngliche Frage. In diesem Fall (obj Instanz von A) würde auch "true" ausgegeben, aber die Absicht ist, die Laufzeitklasse des Objekts im Bild zu finden. Wenn Parent1 um Child1 und Child2 erweitert wird, versuchen Sie Folgendes: code Child1 child1 = new Child1 (); Parent1 parentChild = new Child2 (); Child2 child2 = new Child2 (); (child1-Instanz von Parent1); (child1 Instanz von Child1); (parentChild-Instanz von Child2); (parentChild-Instanz von Parent1); (parentChild-Instanz von Child1); code kann es die Absicht der Instanz von löschen.
Bhavesh Agarwal

Auf jeden Fall eine Alternative zum
Erstellen

3
Was ist, wenn zwei Klassen eine einzige Schnittstelle implementieren? Wie unterscheide ich die genaue Klasse des Objekts?
Olyv

3
Eines jedoch funktioniert es nicht, wenn obj null ist. Die Lösung wäre dann ParentInterface.class.isAssignableFrom (Child.class)
alexbt


178

Es wurden mehrere richtige Antworten präsentiert, aber es gibt noch mehr Methoden: Class.isAssignableFrom()und einfach zu versuchen, das Objekt zu werfen (was ein werfen könnte ClassCastException).

Mögliche Wege zusammengefasst

Lassen Sie uns die möglichen Möglichkeiten zum Testen zusammenfassen, ob ein Objekt objeine Instanz vom Typ ist 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) {
}

Unterschiede in der nullHandhabung

Es gibt jedoch einen Unterschied in der nullHandhabung:

  • In den ersten zwei Methoden Ausdrücke auswerten zu , falsewenn objist null( nullnicht Instanz von irgendetwas ist).
  • Die 3. Methode würde NullPointerExceptionoffensichtlich einen werfen .
  • Die 4. und 5. Methode akzeptieren im Gegenteil, nullweil nullauf jeden Typ gegossen werden kann!

Zu beachten: null ist keine Instanz eines Typs, kann aber in einen beliebigen Typ umgewandelt werden.

Anmerkungen

  • Class.getName()sollte nicht verwendet werden, um einen "is-instance-of" -Test durchzuführen, da das Objekt, wenn es nicht vom Typ, Csondern von einer Unterklasse ist, möglicherweise einen völlig anderen Namen und ein anderes Paket hat (daher stimmen Klassennamen offensichtlich nicht überein) immer noch vom Typ C.
  • Aus dem gleichen Grund Class.isAssignableFrom()ist der Vererbungsgrund nicht symmetrisch :
    obj.getClass().isAssignableFrom(C.class)würde zurückgeben, falsewenn der Typ von objeine Unterklasse von ist C.

6
Dies ist eine wirklich gute Zusammenfassung vieler Fallstricke bei den verschiedenen Methoden. Vielen Dank für dieses vollständige Schreiben!
Kelsin

32

Sie können verwenden:

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

HTH. Aber ich denke, die meiste Zeit ist es keine gute Praxis, dies für den Kontrollfluss oder ähnliches zu verwenden ...


Ich habe es verwendet, um einen generischen Logger zu erstellen. Also habe ich ein Objekt an den Logger gesendet, und es wird abhängig vom Klassennamen des Objekts protokolliert, anstatt jedes Mal ein Log-Tag oder eine Log-Zeichenfolge anzugeben. Vielen Dank
MBH

24

Jede Verwendung einer der vorgeschlagenen Methoden wird als Codegeruch betrachtet, der auf einem schlechten OO-Design beruht.

Wenn Ihr Design gut ist, sollten Sie nicht feststellen, dass Sie getClass()oder verwenden müssen instanceof.

Jede der vorgeschlagenen Methoden reicht aus, aber nur etwas, das Sie in Bezug auf das Design beachten sollten.


3
Ja, wahrscheinlich können 99% der Verwendungen von getClass und instanceof mit polymorphen Methodenaufrufen vermieden werden.
Bill the Lizard

3
Ich bin einverstanden. In diesem Fall arbeite ich mit Objekten, die aus XML generiert wurden, nach einem schlecht gestalteten Schema, an dem ich nicht beteiligt bin.
Träger

28
Nicht unbedingt. Manchmal ist die Trennung von Schnittstellen gut. Es gibt Zeiten, in denen Sie wissen möchten, ob A ein B ist, aber Sie möchten nicht festlegen, dass A ein B ist, da für die meisten Funktionen nur A erforderlich ist - B verfügt über optionale Funktionen.
MetroidFan2002

8
Es gibt auch Zeiten, in denen Sie sicherstellen müssen, dass das Objekt derselben Klasse angehört, mit der Sie vergleichen. Zum Beispiel überschreibe ich gerne die Methode equals von Object, wenn ich meine eigene Klasse erstelle. Ich überprüfe immer, ob das eingehende Objekt derselben Klasse angehört.
StackOverflowed

58
Außerdem würde ich sagen, dass es schlecht ist, Menschen etwas zu erzählen, ohne genau zu erklären, warum oder einen Verweis auf ein Papier, ein Buch oder eine andere Ressource zu geben, in der das Problem erklärt wird. Da ich weiß, dass ich in StackOverflow bin, weiß ich nicht, warum die Leute diese Antwort so sehr positiv bewertet haben. Hier ändert sich etwas ...
Adrián Pérez

15

In diesem Fall können wir Reflexion verwenden

objectName.getClass().getName();

Beispiel:-

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

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

In diesem Fall erhalten Sie den Namen der Klasse, die das Objekt an die HttpServletRequestSchnittstellenreferenzvariable übergibt.


das ist richtig. Nur mit obj.getClass()wird der Klassenname, Präfixex durch das Wortclass
x6iae

request.getClass().getName();druckt alle Pakete! zusammen mit Klassennamen
shareef

13

Es gibt auch eine .isInstanceMethode für die ClassKlasse " ". Wenn Sie die Klasse eines Objekts über erhalten myBanana.getClass(), können Sie sehen, ob Ihr Objekt myAppleeine Instanz derselben Klasse wie myBananaüber ist

myBanana.getClass().isInstance(myApple)

1

Das Überprüfen mit isinstance()würde nicht ausreichen, wenn Sie zur Laufzeit wissen möchten. verwenden:

if(someObject.getClass().equals(C.class){
    // do something
}

0

Ich verwende die Blow-Funktion in meiner GeneralUtils-Klasse. Überprüfen Sie, ob sie nützlich sein kann

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

0

Ich habe Java 8-Generika verwendet, um die Objektinstanz zur Laufzeit abzurufen, anstatt Switch Case verwenden zu müssen

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

Übergeben Sie einen beliebigen Datentyp, und die Methode druckt den Datentyp, den Sie beim Aufrufen übergeben haben. z.B

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

Es folgt die Ausgabe

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 []
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.