Ist vor dem Aufruf von instanceof eine Nullprüfung erforderlich?

1354

Wird null instanceof SomeClasszurückkehren falseoder ein werfen NullPointerException?

Johan Lübcke
quelle
Es ist auch 'wichtig' oder zumindest sehr nützlich als 'Best-Practice'-Startzeile (oder sehr früh) für jede Compare- oder Equals- oder ähnliche Methode, die nur für Nicht-Null-Objekte desselben Typs erfolgreich ist, und schützt Sie in einer einzigen Zeile vor den "dummen Fällen". weniger Code = weniger Fehler.
13
Zum Abwägen des "Ist das nützlich?" Debatte - Ich habe noch nie meinen eigenen Java-Code geschrieben (daher weiß ich nicht genau, wo sich die Spezifikationen befinden, und das Kompilieren eines Tests wäre nicht trivial), aber ich konvertiere Java derzeit manuell in JavaScript. Mein Code schlug bei einer Nullreferenz fehl, und wenn ich dies googelte, sah ich die akzeptierte Antwort, die bestätigte, dass es sich um ein erwartetes Verhalten handelte und dass mir eine implizite Nullprüfung fehlte. In meinem Fall sehr nützlich.
Scott Mermelstein

Antworten:

1838

Nein, eine Nullprüfung ist nicht erforderlich, bevor instanceof verwendet wird.

Der Ausdruck x instanceof SomeClassist falsewenn xist null.

Aus der Java-Sprachspezifikation, Abschnitt 15.20.2, "Typvergleichsoperatorinstanz von" :

"Zur Laufzeit ist das Ergebnis des instanceofOperators, truewenn der Wert von RelationalExpression nicht lautetnull und die Referenz in den ReferenceType umgewandelt werden kann, ohne a auszulösen ClassCastException. Andernfalls ist das Ergebnis false."

Wenn der Operand also null ist, ist das Ergebnis falsch.

Andy Thomas
quelle
377
Diese Antwort ist korrekter als try itweil das aktuelle Verhalten nicht mit dem garantierten Verhalten identisch ist .
Luke
3
Diese Frage kommt während Joshua Blochs Kapitel über Objektgleichheit in Effective Java- amazon.com/Effective-Java-Edition-Joshua-Bloch/dp/0321356683
Kevin Meredith
17
Insbesondere stellt er in Punkt 8 fest, dass bei equals () -Methoden eine Instanz des Operators zwei Zwecken dient - sie überprüft, ob das Argument sowohl nicht null als auch vom richtigen Typ ist. "... [S] o du brauchst keine separate Nullprüfung."
Andy Thomas
2
@BenThurley - Javas instanceofOperator war Teil von Java 1.0, das vor fast 20 Jahren veröffentlicht wurde. Es ist unwahrscheinlich, das Verhalten jetzt so zu ändern, dass der vorhandene Code beschädigt wird, ohne dass ein Vorteil vorliegt, der die enormen Kosten überwiegt. Vor zwanzig Jahren gab es möglicherweise Argumente für die Rückgabe von true, wenn das Argument umgewandelt werden konnte, oder für die Auslösung einer Ausnahme für ein Nullargument. Diese Definitionen hätten jedoch separate Nullprüfungen erforderlich gemacht.
Andy Thomas
3
@BenThurley - Das Verhalten wird durch frühere und aktuelle Java-Spezifikationen garantiert. Ich denke, Lukes Punkt befasst sich mit den Grenzen des Experimentierens bei der Bestimmung des garantierten Verhaltens der Gegenwart.
Andy Thomas
267

Verwenden einer Nullreferenz als ersten Operanden, der instanceofzurückgegeben wird false.

Bozho
quelle
268
(Und jetzt dauert es 10 Sekunden, um diese Frage in Google zu finden)
PL_kolek
73

Sehr gute Frage. Ich habe es nur selbst versucht.

public class IsInstanceOfTest {

    public static void main(final String[] args) {

        String s;

        s = "";

        System.out.println((s instanceof String));
        System.out.println(String.class.isInstance(s));

        s = null;

        System.out.println((s instanceof String));
        System.out.println(String.class.isInstance(s));
    }
}

Druckt

true
true
false
false

JLS / 15.20.2. Typvergleich Operator-Instanz von

Zur Laufzeit ist das Ergebnis des instanceofOperators, truewenn der Wert von RelationalExpression nicht lautet nullund die Referenz in den ReferenceType umgewandelt werden kann, ohne a auszulösen ClassCastException. Ansonsten ist das Ergebnis false.

API / Klasse # isInstance (Objekt)

Wenn dieses ClassObjekt eine Schnittstelle darstellt, gibt diese Methode zurück, truewenn die Klasse oder eine Oberklasse des angegebenen ObjectArguments diese Schnittstelle implementiert. es kehrt falseanders zurück. Wenn dieses ClassObjekt einen primitiven Typ darstellt, gibt diese Methode zurück false.

Jin Kwon
quelle
Irgendwie verwirrend. s ist ein String, weil dort "String s" steht, s ist kein String, weil er null ist. Also, was zum Teufel ist s?
Kai Wang
1
@KaiWang sist nur eine Objektreferenzvariable. Es kann auf ein tatsächlich vorhandenes Objekt ( "") oder auf eine (die) nullLiteralreferenz verweisen.
Jin Kwon
Ich bin immer noch verwirrt. s ist jetzt möglicherweise null, kann aber erst später auf eine String-Instanz verwiesen werden. Es kann nicht auf eine Ganzzahl hingewiesen werden. Es ist also immer noch eine Art String, auch wenn es eine Null ist. Macht einfach nicht viel Sinn ...
Kai Wang
@KaiWang Sie verwechseln den Variablentyp mit dem Typ des tatsächlichen Objekts. Variablen sind keine Instanzen. Sie sind praktisch nur Zeiger. nullsind keine Zeichenfolgendaten, egal welche Variable darauf zeigt. s instanceof Stringist nicht dasselbe wie field.getType().equals(String.class)zum Beispiel.
Matthew Read
@KaiWang Sie müssen sich vorstellen , dass in dem Aufruf s instanceof Stringder smit dem aktuellen Wert ersetzt wird, so dass würde "" instanceof Stringund null instanceof String. So darüber nachzudenken kann sinnvoller sein.
Timo Türschmann
24

Nein, ist es nicht. instanceofwürde zurückkehren, falsewenn sein erster Operand ist null.

RoflcoptrException
quelle
16

Nur als Leckerbissen :

Auch wird zurückkehren .(((A)null)instanceof A)false


(Wenn Typografie nullüberraschend erscheint, müssen Sie dies manchmal tun, beispielsweise in Situationen wie diesen:

public class Test
{
  public static void test(A a)
  {
    System.out.println("a instanceof A: " + (a instanceof A));
  }

  public static void test(B b) {
    // Overloaded version. Would cause reference ambiguity (compile error)
    // if Test.test(null) was called without casting.
    // So you need to call Test.test((A)null) or Test.test((B)null).
  }
}

So Test.test((A)null)wird gedruckt a instanceof A: false.)


PS: Wenn Sie einstellen, verwenden Sie dies bitte nicht als Frage für ein Vorstellungsgespräch. : D.

Attila Tanyi
quelle
7

Nein . Java-Literal nullist keine Instanz einer Klasse. Daher kann es keine Instanz einer Klasse sein. instanceof gibt entweder falseodertrue daher die <referenceVariable> instanceof <SomeClass>Rückgabe zurück, falsewenn der referenceVariableWert null ist.

Entwickler Marius Žilėnas
quelle
5
Diese Erklärung klingt seltsam kreisförmig ... aber ich weiß, was du meinst :-)
Kris
@Kris ty für den Kommentar Ich habe was du meinst :). Antwort ein bisschen bearbeitet :).
Entwickler Marius Žilėnas
1

Der instanceofOperator benötigt keine expliziten nullÜberprüfungen, da er kein a auslöst, NullPointerExceptionwenn der Operand ist null.

Zur Laufzeit ist das Ergebnis des instanceofOperators wahr, wenn der Wert des relationalen Ausdrucks nicht stimmt nullund die Referenz in den Referenztyp umgewandelt werden kann, ohne eine Klassenumwandlungsausnahme auszulösen.

Wenn dies der Operand ist null, gibt der instanceofOperator zurück falseund daher sind keine expliziten Nullprüfungen erforderlich.

Betrachten Sie das folgende Beispiel:

public static void main(String[] args) {
         if(lista != null && lista instanceof ArrayList) {                     //Violation
                System.out.println("In if block");
         }
         else {
                System.out.println("In else block");
         }
}

Die korrekte Verwendung von instanceofist wie unten gezeigt,

public static void main(String[] args) {
      
         if(lista instanceof ArrayList){                     //Correct way
                  System.out.println("In if block");
         }
            else {
                 System.out.println("In else block");
         }  
}
Nikhil Kumar
quelle