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?

Träger
quelle
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
}
IAdapter
quelle
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
351

Verwenden Sie Object.getClass () . Es gibt den Laufzeittyp des Objekts zurück.

Bill die Eidechse
quelle
12
So bestimmen Sie tatsächlich die Klasse eines Objekts
AA_PV
makellose Antwort @ Bill
Gaurav
1
Ich
bin
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.
icza
quelle
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 ...

Johannes Weiss
quelle
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.

Yuval Adam
quelle
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.

user1884500
quelle
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)
Andreas Petersson
quelle
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
}
Alon Gouldman
quelle
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();
}
Ahmed Salem
quelle
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 []
Saurabh Verma
quelle