Java: Class.isInstance vs Class.isAssignableFrom

232

Lass clazzeinige sein Classund objeinige sein Object.

Ist

clazz.isAssignableFrom(obj.getClass())

immer das gleiche wie

clazz.isInstance(obj)

?

Wenn nicht, was sind die Unterschiede?

Albert
quelle
25
Wenn obj == null, gibt der zweite false zurück, der erste nicht. ;)
Peter Lawrey
21
@ PeterLawrey, der erste wird ein NullPointerExceptionWenn werfen obj == null.
Ryvantage
Ich habe eine Antwort mit Beispielen von hrere gefunden: mytechnotes.biz/2012/07/…
Paramesh Korrakuti
4
An die Leser: Sie sind dabei, ein tiefes, dunkles, schwarzes Loch zu betreten, aus dem Sie niemals entkommen werden. Die Unterschiede sind endlos. Gib jetzt auf, solange du noch kannst: stackoverflow.com/q/496928/1599699
Andrew
@ParameshKorrakuti Der Domainname ändert sich in tshikatshikaaa.blogspot.com/2012/07/…
Jérôme Verstrynge

Antworten:

222

clazz.isAssignableFrom(Foo.class)wird immer dann wahr sein, wenn die durch das clazzObjekt dargestellte Klasse eine Superklasse oder Superschnittstelle von ist Foo.

clazz.isInstance(obj)wird wahr sein, wenn das Objekt objeine Instanz der Klasse ist clazz.

Das ist:

clazz.isAssignableFrom(obj.getClass()) == clazz.isInstance(obj)

ist immer wahr, solange clazzund objnicht null.

uckelman
quelle
3
Dies übersieht den Fall, in dem der Foo derselbe wie der Clazz ist - in diesem Fall gibt er wahr zurück: Pauls Antwort mit der höchsten Stimme unten korrigiert dies
Rhabarber
3
Ich bin damit einverstanden, dass wenn clazz ein Foo ist, clazz.isAssignableFrom (Foo.class) wahr ist. Wo habe ich etwas anderes gesagt?
uckelman
5
@Gili Das hat uckelman nicht gesagt. Bitte lesen Sie seine Antwort noch einmal.
Puce
2
Byte b = 3; Comparable.class.isAssignableFrom(b.getClass()) == Comparable.class.isInstance(b)); -> das gilt auch für schnittstellen.
Puce
1
Technik: Wenn objist nulldann clazz.isAssignableFrom(obj.getClass()) == clazz.isInstance(obj)wird ein werfen NullPointerExceptionund nicht zurückkehren true.
Andrew Macheret
196

Beide Antworten befinden sich im Ballpark, aber keine ist eine vollständige Antwort.

MyClass.class.isInstance(obj)dient zum Überprüfen einer Instanz. Es gibt true zurück, wenn der Parameter obj nicht null ist und MyClassohne Erhöhen von a umgewandelt werden kann ClassCastException. Mit anderen Worten, obj ist eine Instanz MyClassoder deren Unterklassen.

MyClass.class.isAssignableFrom(Other.class)wird true zurückgeben, wenn MyClasses dasselbe ist wie oder eine Superklasse oder Superschnittstelle von , Other. Otherkann eine Klasse oder eine Schnittstelle sein. Es antwortet wahr, wenn Otherin a konvertiert werden kann MyClass.

Ein kleiner Code zur Demonstration:

public class NewMain
{
    public static void main(String[] args)
    {
        NewMain nm = new NewMain();
        nm.doit();
    }

    class A { }

    class B extends A { }

    public void doit()
    {
        A myA = new A();
        B myB = new B();
        A[] aArr = new A[0];
        B[] bArr = new B[0];

        System.out.println("b instanceof a: " + (myB instanceof A)); // true
        System.out.println("b isInstance a: " + A.class.isInstance(myB)); //true
        System.out.println("a isInstance b: " + B.class.isInstance(myA)); //false
        System.out.println("b isAssignableFrom a: " + A.class.isAssignableFrom(B.class)); //true
        System.out.println("a isAssignableFrom b: " + B.class.isAssignableFrom(A.class)); //false
        System.out.println("bArr isInstance A: " + A.class.isInstance(bArr)); //false
        System.out.println("bArr isInstance aArr: " + aArr.getClass().isInstance(bArr)); //true
        System.out.println("bArr isAssignableFrom aArr: " + aArr.getClass().isAssignableFrom(bArr.getClass())); //true
    }
}
Paul
quelle
10
Warum in Ihrem Beispiel "b isAssignableFrom a:", aber Code ist A.class.isAssignableFrom(B.class)? Ich verwirrt durch Ausgabe :)
Roman Truba
4
ummm ... in all Ihren Beispielen gibt "instanceOf" true zurück, wenn "isAssignableFrom" true zurückgibt ... Ich sehe den Unterschied nicht so.
Android-Entwickler
2
Achten Sie darauf, dass der ausgedruckte Text nicht mit dem Code übereinstimmt und verwirrend sein kann ... Beispiel: "System.out.println (" b isAssignableFrom a: "+ A.class.isAssignableFrom (B.class));"
Polster
21
@Paul Die Antwort ist nicht hilfreich, da sich der Leser fragt: "Was ist der Unterschied zwischen einem Objekt, das eine Instanz einer Unterklasse einer Klasse ist, und dem Objekttyp, der in die Klasse konvertierbar ist?" Sicherlich können Sie sehen, dass Sie dem Leser nach dem Lesen Ihrer Antwort so viele Fragen hinterlassen haben, wie er bei der Ankunft auf dieser Seite hatte. Eine bessere Antwort würde tatsächlich den Unterschied (oder das Fehlen davon) erklären. Wenn es keinen Unterschied gibt, sollte in der Antwort direkt angegeben werden: "Es gibt keinen praktischen Unterschied."
Aleksandr Dubinsky
2
Noch wichtiger ist, dass sich der Leser die Frage stellt, was zum Teufel er für seine Zwecke verwenden soll. Nach den Kommentaren in der Frage, isAssignableFrom()wirft ein , NullPointerExceptionwenn das Objekt null ist, während isInstance()nur false zurückgibt. Das ist die wahre Antwort.
Andrew
6

Ich denke, das Ergebnis für diese beiden sollte immer das gleiche sein. Der Unterschied besteht darin, dass Sie eine Instanz der Klasse benötigen, isInstanceaber nur das Classzu verwendende Objekt isAssignableFrom.

ColinD
quelle
Dies ist nicht 100% wahr. Comparable.class.isAssignableFrom(Byte.class) == trueaber Byte.class.isInstance(Comparable.class) == false. Mit anderen Worten, isInstance()ist nicht symmetrisch für Schnittstellen, sondern nur für Unterklassen.
Gili
6
@Gili: Da hast du ein bisschen was falsch gemacht. Byte.class.isInstance(Comparable.class)ist falsch, weil ein ClassObjekt keine Instanz von ist Byte. Der richtige Vergleich zu Comparable.class.isAssignableFrom(Byte.class)ist Comparable.class.isInstance((byte) 1), was wahr ist.
ColinD
1
Ich bin nicht einverstanden. Wenn Sie den Javadoc von Ihnen nachschlagen, werden ByteSie feststellen, dass er sich ausdehnt Numberund eine Klasse ist. (byte) 1ist nicht gleichbedeutend mit Byte. Ersteres ist ein Primitiv. Letzteres ist eine Klasse.
Gili
2
@Gili: Autoboxing wirkt primitiv byte, Byteweil der Parametertyp von isInstanceist Object.
ColinD
2
In Ordnung. Mein ursprünglicher Punkt war, dass die Anrufe nicht genau symmetrisch zueinander sind, aber nachdem Sie Ihre Antwort erneut gelesen haben, haben Sie diese Behauptung nie gemacht, also haben Sie Recht.
Gili
6

Der Kürze halber können wir diese beiden APIs wie folgt verstehen:

  1. X.class.isAssignableFrom(Y.class)

Wenn Xund Yderselben Klasse sind, oder Xist Y‚s Superklasse oder Superschnittstelle, return true, andernfalls false.

  1. X.class.isInstance(y)

Say yist eine Instanz der Klasse Y, wenn Xund Yderselben Klasse sind, oder Xist Y‚s Superklasse oder Superschnittstelle, true zurück, andernfalls false.

Sonnig
quelle