Pierwszą rzeczą, o której należy pamiętać, jest to, że trójskładnikowe operatory Java mają „typ”, i to właśnie kompilator określi i rozważy bez względu na rzeczywiste / rzeczywiste typy drugiego lub trzeciego parametru. W zależności od kilku czynników typ operatora trójskładnikowego określa się na różne sposoby, jak pokazano w specyfikacji języka Java 15.26
W powyższym pytaniu powinniśmy rozważyć ostatni przypadek:
W przeciwnym razie drugi i trzeci argument są odpowiednio typu S1 i S2 . Niech T1 będzie typem wynikającym z zastosowania konwersji boksu do S1 , i niech T2 będzie typem wynikającym z zastosowania konwersji boksu do S2 . Rodzaj wyrażenia warunkowego wynika z zastosowania konwersji przechwytywania (§5.1.10) na lub (T1, T2) (§15.12.2.7).
Jest to zdecydowanie najbardziej złożony przypadek, gdy przyjrzysz się zastosowaniu konwersji przechwytywania (§ 5.1.1), a przede wszystkim w lub (T1, T2) .
Prostym językiem angielskim i po skrajnym uproszczeniu możemy opisać ten proces jako obliczenie „najmniejszej wspólnej superklasy” (tak, pomyśl o LCM) drugiego i trzeciego parametru. To da nam trójskładnikowy „typ”. Ponownie, to, co właśnie powiedziałem, jest ekstremalnym uproszczeniem (rozważ klasy, które implementują wiele popularnych interfejsów).
Na przykład, jeśli spróbujesz:
long millis = System.currentTimeMillis();
return(true ? new java.sql.Timestamp(millis) : new java.sql.Time(millis));
Zauważysz, że wynikowym typem wyrażenia warunkowego jest java.util.Dateto, że jest to „Najmniejsza wspólna nadklasa” dla pary Timestamp/ Timepair.
Ponieważ nullmoże być autoboxowane do czegokolwiek, „Least Common Superclass” jest Integerklasą i będzie to zwracany typ wyrażenia warunkowego (operator trójskładnikowy) powyżej. Zwracana wartość będzie wtedy zerowym wskaźnikiem typu Integeri to, co zostanie zwrócone przez operator trójskładnikowy.
W czasie wykonywania, gdy wirtualna maszyna Java się rozpakowuje, wyrzucane jest Integera NullPointerException. Dzieje się tak, ponieważ JVM próbuje wywołać funkcję null.intValue(), gdzie nulljest wynikiem autoboxowania.
Moim zdaniem (a ponieważ mojej opinii nie ma w specyfikacji języka Java, wiele osób i tak uzna to za błędne), kompilator źle radzi sobie z oceną wyrażenia w pytaniu. Biorąc pod uwagę, że napisałeś, true ? param1 : param2kompilator powinien od razu ustalić, że pierwszy parametr - null- zostanie zwrócony i powinien wygenerować błąd kompilatora. Jest to nieco podobne do tego, kiedy piszesz, while(true){} etc...a kompilator narzeka na kod pod pętlą i oznacza go flagą Unreachable Statements.
Druga sprawa jest dość prosta i ta odpowiedź jest już za długa ...;)
KOREKTA:
Po kolejnej analizie uważam, że nie miałem racji, twierdząc, że nullwartość może być spakowana / autoboxed do dowolnego elementu. Mówiąc o klasie Integer, jawne boksowanie polega na wywołaniu new Integer(...)konstruktora, a może Integer.valueOf(int i);(znalazłem tę wersję gdzieś). Pierwsze rzuciłoby NumberFormatException(i tak się nie dzieje), a drugie nie miałoby sensu, ponieważ intnie można null...
int foo = (true ? null : 0)inew Integer(null)zarówno kompilacji porządku, druga jest wyraźne forma autoboxing.