Czy konieczne jest sprawdzenie wartości zerowej przed wywołaniem instanceof?

1354

Będzie null instanceof SomeClasspowrotu falselub rzucić NullPointerException?

Johan Lübcke
źródło
Jest także „ważny” lub przynajmniej bardzo przydatny jako „najlepsza praktyka” linia początkowa (lub bardzo wczesna) dla każdego porównania lub równej lub podobnej metody, która została zaprojektowana tak, aby odniosła sukces tylko na obiektach tego samego typu niepustych oraz chroni cię przed „głupimi przypadkami” w jednej linii. mniej kodu = mniej błędów.
13
Zastanowić się nad „czy to jest przydatne?” debata - Nigdy nie napisałem własnego kodu Java (więc nie wiem, gdzie są specyfikacje, a skompilowanie testu byłoby bardzo nietrywialne), ale obecnie ręcznie konwertuję Javę na JavaScript. Mój kod zawiódł w odwołaniu zerowym i przeglądanie go pozwoliło mi zobaczyć zaakceptowaną odpowiedź, która potwierdziła, że ​​było to oczekiwane zachowanie i że brakowało mi niejawnego sprawdzenia zerowego. Bardzo przydatne w moim przypadku.
Scott Mermelstein

Odpowiedzi:

1838

Nie, sprawdzanie wartości zerowej nie jest konieczne przed użyciem instanceof.

Wyrażenie x instanceof SomeClassto falsejeśli xjest null.

Ze specyfikacji języka Java, sekcja 15.20.2, „Instancja operatora porównania typów” :

„W czasie wykonywania wynikiem działania instanceofoperatora jest to, trueczy wartość RelationalExpression nie jest,null a odwołanie może być rzutowane na ReferenceType bez podnoszenia a ClassCastException. W przeciwnym razie wynik jest false.”

Jeśli więc argument jest pusty, wynik jest fałszywy.

Andy Thomas
źródło
377
Ta odpowiedź jest bardziej poprawna niż try itdlatego, że obecne zachowanie nie jest tym samym, co zachowanie gwarantowane .
Łukasz
3
To pytanie pojawia się w rozdziale Joshua Blocha na temat równości obiektów w Effective Java- amazon.com/Effective-Java-Edition-Joshua-Bloch/dp/0321356683
Kevin Meredith
17
W szczególności w punkcie 8 zauważa, że ​​w metodach equals () jedno wystąpienie operatora służy dwóm celom - sprawdza, czy argument nie jest zerowy i ma poprawny typ. „... [S] o nie potrzebujesz osobnego czeku zerowego.”
Andy Thomas
2
@BenThurley - instanceofoperator Javy był częścią Java 1.0, wydanej prawie 20 lat temu. Zmiana zachowania teraz w sposób, który zniszczyłby istniejący kod, jest mało prawdopodobna, ponieważ nie przynosi korzyści przewyższających tak ogromne koszty. Dwadzieścia lat temu być może istniałyby argumenty za zwróceniem prawdziwego, jeśli argument mógłby zostać rzucony, lub wprowadzenie wyjątku dla argumentu zerowego. Ale te definicje wymagałyby osobnych kontroli zerowych.
Andy Thomas
3
@BenThurley - Zachowanie jest gwarantowane przez przeszłe i obecne specyfikacje Java. Myślę, że punkt Łukasza odnosi się do ograniczeń eksperymentów w określaniu gwarantowanego zachowania teraźniejszości.
Andy Thomas
267

Użycie odwołania zerowego jako pierwszego argumentu operacji do instanceofzwrócenia false.

Bozho
źródło
268
(A teraz znalezienie tego pytania w Google zajmuje 10 sekund)
PL_kolek
73

Rzeczywiście bardzo dobre pytanie. Właśnie próbowałem dla siebie.

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

Wydruki

true
true
false
false

JLS / 15.20.2. Porównanie typów Operator instanceof

W czasie wykonywania wynik instanceofoperatora jest truetaki, że wartość RelationalExpression nie jest, nulla odwołanie może być rzutowane na ReferenceType bez podnoszenia a ClassCastException. W przeciwnym razie wynik jest false.

API / Class # isInstance (Object)

Jeśli ten Classobiekt reprezentuje interfejs, ta metoda zwraca, truejeśli klasa lub jakakolwiek nadklasa określonego Objectargumentu implementuje ten interfejs; zwraca falseinaczej. Jeśli ten Classobiekt reprezentuje typ pierwotny, ta metoda zwraca false.

Jin Kwon
źródło
Trochę mylące. s jest ciągiem, ponieważ mówi „ciąg s”, s nie jest ciągiem, ponieważ jest pusty. Co to do cholery jest?
Kai Wang,
1
@KaiWang sjest tylko zmienną odwołania do obiektu. Może odwoływać się do faktycznie istniejącego obiektu ( "") lub może odnosić się do nulldosłownego odwołania.
Jin Kwon
Wciąż jestem zdezorientowany. s może teraz mieć wartość NULL, ale można go później wskazać na instancję klasy String. Nie można wskazać na liczbę całkowitą. Więc nadal jest rodzajem String, nawet jeśli jest zerowy. Po prostu nie ma większego sensu ...
Kai Wang
@KaiWang Mylisz typ zmiennej z typem rzeczywistego obiektu. Zmienne nie są instancjami; są po prostu wskaźnikami. nullnie jest ciągiem danych, bez względu na to, która zmienna na to wskazuje. s instanceof Stringto nie to samo, co field.getType().equals(String.class)na przykład.
Mateusz
@KaiWang trzeba sobie wyobrazić, że w zaproszeniu zostanie zastąpiony wartością rzeczywistą, tak że stałby się i . Takie myślenie może mieć większy sens. s instanceof Strings"" instanceof Stringnull instanceof String
Timo Türschmann
24

Nie, nie jest. instanceofzwróci, falsejeśli jest to pierwszy argument operacji null.

RoflcoptrException
źródło
16

Tak jak smakołyk :

Nawet wróci .(((A)null)instanceof A)false


(Jeśli rzutowanie nullwydaje się zaskakujące, czasami musisz to zrobić, na przykład w sytuacjach takich jak ta:

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

Więc Test.test((A)null)wydrukuję a instanceof A: false.)


PS: Jeśli zatrudniasz, nie używaj tego jako pytania do rozmowy kwalifikacyjnej. :RE

Attila Tanyi
źródło
7

Nie . Literał Java nullnie jest instancją żadnej klasy. Dlatego nie może być instancją żadnej klasy. instanceof zwróci jeden falselubtrue dlatego <referenceVariable> instanceof <SomeClass>zwraca, falsegdy referenceVariablewartość jest null.

Deweloper Marius Žilėnas
źródło
5
To wyjaśnienie brzmi dziwnie koliście ... ale wiem, co masz na myśli :-)
Kris
@Kris ty za komentarz Mam to, co masz na myśli :). Zmodyfikowałem nieco odpowiedź :).
Deweloper Marius Žilėnas
1

instanceofOperator nie musi jawne nullkontrole, a nie rzucać NullPointerExceptionjeśli argument jestnull .

W czasie wykonywania wynik instanceofoperatora jest prawdziwy, jeśli wartość wyrażenia relacyjnego nie jest, nulla odwołanie można rzutować na typ odwołania bez zgłaszania wyjątku rzutowania na klasę.

Jeśli operand jest null, instanceofoperator zwraca, falsea zatem jawne sprawdzanie wartości NULL nie jest wymagane.

Rozważ poniższy przykład

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

Prawidłowe użycie instanceofjest pokazane poniżej,

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
źródło