2015-01-27 16 views
8

Dlaczego poniższe wywołanie wyjątku NullPointerException? :Wyjątek NullPointerException w typie zwracającym typ Obiekt

public static Object myTest() { 
    boolean x = false; 
    boolean y = false; 
    return x && y ? new Object() : x ? x : y ? y : null; 
} 

public static void main(String [ ] args) { 
    myTest(); 
} 

wiem czy zrobić jedną z następujących czynności kod nie będzie rzucać NullPointerException:

A)

public static Object myTest() { 
    boolean x = false; 
    boolean y = false; 
    return x && y ? new Object() : x ? x : y ? y : (Object) null; 
} 

public static void main(String [ ] args) { 
    myTest(); 
} 

B)

public static Object myTest() { 
    Boolean x = false; 
    Boolean y = false; 
    return x && y ? new Object() : x ? x : y ? y : null; 
} 

public static void main(String [ ] args) { 
    myTest(); 
} 

Ponadto, jeśli zmienię cod e całkowicie i wykonaj następujące działania:

public static Object myTest() { 
    boolean x = false; 
    boolean y = false; 

    if(x && y) { 
     return new Object(); 
    } else if(x) { 
     return x; 
    } else if(y) { 
     return y; 
    } else { 
     return null; 
    } 
} 

public static void main(String [ ] args) { 
    myTest(); 
} 

Chyba kompilator robi jakąś optymalizację i jakoś brudząc rzeczy? Zakładam, że jest to jakiś problem z odlewaniem, ale dlaczego w takim przypadku wyrzuciłby wyjątek NullPointerException zamiast wyjątku ClassCastException? Wszelkie informacje o tym, dlaczego tak się dzieje, byłyby bardzo cenne!

góry dzięki

+0

To rzucanie Wyjątek NullPointerException, ponieważ w tym paskudnym bałaganie jest pusty wskaźnik. –

+0

To jest to, co początkowo myślałem, ale myślę, że warto na nie patrzeć, więc +1 – Bathsheba

+0

@laune, rzuca 'NullPointerException'. –

Odpowiedz

6

Jeśli dodać trochę nawias dla czytelności:

return (x && y) ? (new Object()) : (x ? x : (y ? y : null)); 

Widać, że w y ? y : null, kompilator będzie próbował unbox null (tak, że typy dopasowania), powodując NPE do rzucenia.

+2

do wypełnienia: typ 'y: null' jest ustawiony przez' y', ponieważ lewy operand ma wartość null. Jeśli dodasz '(Object) null', ustawisz typ, zapobiegając autounboxingowi do' boolean', i jeśli dodasz 'Boolean y', to unboxing nie jest potrzebny, ponieważ' null' pasuje do typu 'Boolean'. – njzk2

+2

po przetestowaniu, NPE najwyraźniej dzieje się w '(x? X: ...)', ponieważ kompilator myśli, że wynik '(y? Y: null)' musi być 'boolean' – njzk2

+1

@ njzk2 Może to być związane z http : //stackoverflow.com/questions/3882095/booleans-conditional-operators-and-autoboxing, jeśli potraktujemy '(y? y: null)' jako odpowiednik 'zwracaNull()' (ale jeszcze jej nie przeczytałem więc mogę się mylić). – Pshemo

1

(ten kod jest nieczytelny i prawdopodobnie należy go unikać), ale aby rzeczywiście odpowiedzieć: Jak wyżej, rozumowanie ma związek z autoboxingiem i rozpakowywaniem oraz kompilatorem wykonującym kontrole. To tak, jakbyś napisał boolean b = (Boolean) null, który w czasie wykonywania rzuci NPE.

W przykładzie A, rzuca się go do obiektu jawnie, więc nie dodaje się autoboxingu.

W przykładzie B wszystko już jest obiektem (boolean jest prymitywny, a Boolean jest obiektem), więc znowu nie ma boksu ani rozpakowywania.

Wreszcie, w przykładzie C nie ma żadnego rozpakowywania, a zamiast tego wynik jest po prostu w pudełku po jego zwróceniu. (jeśli-else rozgałęzienie umożliwia kompilatorowi sprawdzenie każdej gałęzi indywidualnie, zamiast potrójnych operatorów, które wymagają odgadnięcia całej instrukcji, a następnie przypisania całego zdania typu, co ma związek z wypowiedziami a wyrażeniami i całą dziwnością w przepisach autoboxing i rodzaj sprawdzania Java)

(Casting problemy zdarzyć w czasie kompilacji, jeśli spróbujesz nieodpowiedniego obsady jak:. (Boolean) 7 lub w czasie wykonywania, jeśli zrobisz coś takiego:

int c = 7; 
Object co = (Object) c; 
Boolean bco = (Boolean) co; 
Powiązane problemy