Trudny Operator trójkowy w Javie-autoboxing
Spójrzmy na prosty kod Javy w poniższym fragmencie:
public class Main {
private int temp() {
return true ? null : 0;
// No compiler error - the compiler allows a return value of null
// in a method signature that returns an int.
}
private int same() {
if (true) {
return null;
// The same is not possible with if,
// and causes a compile-time error - incompatible types.
} else {
return 0;
}
}
public static void main(String[] args) {
Main m = new Main();
System.out.println(m.temp());
System.out.println(m.same());
}
}
W tym najprostszym kodzie Javy, metoda temp()
nie powoduje błędu kompilatora, mimo że zwracanym typem funkcji jest int
, a my staramy się zwrócić wartość null
(poprzez polecenie return true ? null : 0;
). Po skompilowaniu powoduje to oczywiście wyjątek czasu wykonania NullPointerException
.
Wydaje się jednak, że to samo jest złe, jeśli reprezentujemy operator trójkowy za pomocą if
twierdzenia (jak w same()
metoda), która powoduje błąd w czasie kompilacji! Dlaczego?
8 answers
Kompilator interpretuje null
jako zerowe odniesienie do Integer
, stosuje zasady autoboxingu/unboxingu dla operatora warunkowego (opisane w specyfikacji języka Java , 15.25) i porusza się szczęśliwie dalej. Spowoduje to wygenerowanie NullPointerException
w czasie wykonywania, co można potwierdzić, próbując go.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-18 06:46:08
Myślę, że kompilator Javy interpretuje true ? null : 0
jako wyrażenie Integer
, które może być w domyśle przekonwertowane na int
, ewentualnie dając NullPointerException
.
W drugim przypadku wyrażenie {[4] } jest typu specjalnego null Zobacz , więc kod return null
powoduje niedopasowanie typu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-02 00:59:53
Właściwie wszystko to zostało wyjaśnione w specyfikacji języka Java .
Typ wyrażenia warunkowego określa się następująco:
- jeśli drugi i trzeci operand mają ten sam typ (który może być typem null), to jest to typ wyrażenia warunkowego.
Dlatego "null" w (true ? null : 0)
otrzymuje typ int i jest automatycznie przypisywany do liczby całkowitej.
Spróbuj czegoś takiego, aby to zweryfikować (true ? null : null)
I ty spowoduje błąd kompilatora.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-02 00:57:30
W przypadku twierdzenia if
odniesienie null
nie jest traktowane jako odniesienie Integer
, ponieważ nie uczestniczy w wyrażeniu , które wymusza jego interpretację jako takie. Dlatego błąd może być łatwo wychwycony podczas kompilacji, ponieważ jest to wyraźniejszy błąd typu .
Jeśli chodzi o operator warunkowy, specyfikacja języka Java §15.25 "operator warunkowy ? :
" odpowiada na to ładnie w regułach konwersji typu
- jeśli drugi i trzeci operand mają ten sam typ (który może być null type), wtedy jest to typ wyrażenia warunkowego.
Nie dotyczy, ponieważnull
nie jestint
.
- Jeśli jeden z drugich i trzecich operandów jest typu boolean i typu inne jest typu Boolean, wtedy typem wyrażenia warunkowego jest boolean.
Nie dotyczy, ponieważ aninull
aniint
jestboolean
lubBoolean
.
- Jeśli jeden z drugich i trzecich operandów jest typu null i typu inny jest typem odniesienia, wtedy typ wyrażenia warunkowego jest taki, że Typ odniesienia.
nie ma zastosowania, ponieważ {[1] } jest typu null, aleint
nie jest typem odniesienia.
- W przeciwnym razie, jeśli drugi i trzeci operand mają typy, które są konwertowalne (§5.1.8) do typów liczbowych, wtedy jest kilka przypadków: [...]
stosuje się: {[1] } jest traktowana jako zamienna dla typu liczbowego i jest zdefiniowana w §5.1.8 "Konwersja Unboxing" do wyrzuceniaNullPointerException
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-12 19:07:56
Pierwszą rzeczą, o której należy pamiętać jest to, że operatory trójdzielne Javy mają "typ" i to właśnie kompilator określi i rozważy bez względu na to, jakie są rzeczywiste/rzeczywiste typy drugiego lub trzeciego parametru. W zależności od kilku czynników Typ operatora trójdzielnego jest określany na różne sposoby, jak pokazano w specyfikacji języka Java 15.26
W powyższym pytaniu powinniśmy rozważyć ostatni przypadek:
Inaczej drugi i trzeci operand to odpowiednio typy S1 i S2 . Niech T1 będzie typem wynikającym z zastosowania konwersji boksu do S1 , a T2 będzie typem wynikającym z zastosowania konwersji boksu do S2 . Typ wyrażenia warunkowego jest wynikiem zastosowania konwersji przechwytywania (§5.1.10) do lub (T1, T2) (§15.12.2.7).
Jest to zdecydowanie najbardziej skomplikowana sprawa, gdy spojrzysz na zastosowanie konwersji przechwytywania (§5.1.10) i przede wszystkim na lub (T1, T2).
W prostym języku angielskim i po skrajnym uproszczeniu możemy opisać ten proces jako obliczanie "najmniej wspólnej superklasy" (tak, pomyśl o LCM) drugiego i trzeciego parametru. To da nam trójkowy operator "Typ". Ponownie, to, co właśnie powiedziałem, jest skrajnym uproszczeniem (rozważ klasy, które implementują wiele wspólnych interfejsów).
Na przykład, jeśli spróbuj:
long millis = System.currentTimeMillis();
return(true ? new java.sql.Timestamp(millis) : new java.sql.Time(millis));
Zauważysz, że wynikowy typ wyrażenia warunkowego to java.util.Date
, ponieważ jest to "najmniej powszechna Klasa nadrzędna" dla Timestamp
/Time
para.
Ponieważ null
może być automatycznie przypisana do czegokolwiek, "najmniej powszechną klasą nadrzędną" jest klasa Integer
i będzie to typ zwracany wyrażenia warunkowego (operator trójkowy) powyżej. Zwracana wartość będzie wtedy wskaźnikiem null typu Integer
i to jest to, co zostanie zwrócone przez Trójnik centrala.
Integer
a NullPointerException
jest wyrzucana. Dzieje się tak, ponieważ JVM próbuje wywołać funkcję null.intValue()
, gdzie {[4] } jest wynikiem autoboxingu.
Moim zdaniem (a ponieważ moja opinia nie znajduje się w specyfikacji języka Java, Wiele osób i tak uzna to za złe) kompilator źle ocenia wyrażenie w twoim pytaniu. Biorąc pod uwagę, że napisałeś true ? param1 : param2
kompilator powinien od razu stwierdzić, że pierwszy parametr -null
- zostanie zwrócony i powinien wygenerować błąd kompilatora. Jest to nieco podobne do tego, gdy piszesz while(true){} etc...
, a kompilator narzeka na kod znajdujący się pod pętlą i zaznacza go symbolem Unreachable Statements
.
Twój drugi przypadek jest dość prosty, a ta odpowiedź jest już zbyt długa... ;)
Korekta:
Po kolejnej analizie uważam, że myliłem się mówiąc, że wartość null
może być boxed / autoboxed do czegokolwiek. Mówiąc o class Integer, explicit boxing polega na wywołaniu konstruktora new Integer(...)
lub może Integer.valueOf(int i);
(gdzieś znalazłem tę wersję). Pierwszy rzuci NumberFormatException
(i tak się nie dzieje) , podczas gdy drugi po prostu nie ma sensu, ponieważ int
nie może być null
...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-02 01:08:56
Właściwie w pierwszym przypadku wyrażenie może być obliczone, ponieważ kompilator wie, że musi być obliczone jako Integer
, jednak w drugim przypadku nie można określić typu zwracanej wartości (null
), więc nie można go skompilować. Jeśli wrzucisz go do Integer
, Kod się skompiluje.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-21 19:46:21
private int temp() {
if (true) {
Integer x = null;
return x;// since that is fine because of auto-boxing then the returned value could be null
//in other words I can say x could be null or new Integer(intValue) or a intValue
}
return (true ? null : 0); //this will be prefectly legal null would be refrence to Integer. The concept is one the returned
//value can be Integer
// then null is accepted to be a variable (-refrence variable-) of Integer
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-26 23:23:46
A może tak:
public class ConditionalExpressionType {
public static void main(String[] args) {
String s = "";
s += (true ? 1 : "") instanceof Integer;
System.out.println(s);
String t = "";
t += (!true ? 1 : "") instanceof String;
System.out.println(t);
}
}
Wyjście jest prawdziwe, prawdziwe.
Kolor Eclipse koduje 1 w wyrażeniu warunkowym jako autoboxed.
Domyślam się, że kompilator widzi zwracany typ wyrażenia jako obiekt.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-08 19:40:54