Przede wszystkim mówimy tylko o zmiennych lokalnych . Skutecznie ostateczna nie dotyczy pól. Jest to ważne, ponieważ semantyka finalpól jest bardzo różna i podlega ciężkim optymalizacjom kompilatora i obietnicom modelu pamięci, patrz 17.5.1 na temat semantyki pól końcowych.
Na poziomie powierzchniowym finali effectively finaldla zmiennych lokalnych są rzeczywiście identyczne. Jednak JLS dokonuje wyraźnego rozróżnienia między nimi, co w rzeczywistości ma szeroki zakres efektów w specjalnych sytuacjach, takich jak ta.
Przesłanka
Od JLS§4.12.4 o finalzmiennych:
Zmiennej stałej jest finalzmienne od pierwotnego typu lub typu ciąg , który jest inicjowany przy stałej ekspresji ( §15.29 ). To, czy zmienna jest zmienną stałą, czy nie, może mieć wpływ na inicjalizację klasy ( §12.4.1 ), zgodność binarną ( §13.1 ), osiągalność ( §14.22 ) i określone przypisanie ( §16.1.1 ).
Ponieważ intjest prymitywna, zmienna ajest taką stałą zmienną .
Dalej, z tego samego rozdziału o effectively final:
Niektóre zmienne, które nie zostały uznane za ostateczne, są zamiast tego uważane za faktycznie ostateczne:
Ze sposobu sformułowania tego wynika jasno, że w drugim przykładzie a nie jest uważana za zmienną stałą, ponieważ nie jest ostateczna , a jedynie faktycznie ostateczna.
Zachowanie
Teraz, gdy mamy rozróżnienie, spójrzmy, co się dzieje i dlaczego wynik jest inny.
Używasz operatora warunkowego ? : tutaj , więc musimy sprawdzić jego definicję. Od JLS§15.25 :
Istnieją trzy rodzaje wyrażeń warunkowych, sklasyfikowanych zgodnie z drugim i trzecim wyrażeniem operandowym : logiczne wyrażenia warunkowe , numeryczne wyrażenia warunkowe i wyrażenia warunkowe dotyczące odwołań .
W tym przypadku mówimy o pliku liczbowych wyrażeniach warunkowych z JLS§15.25.2 :
Typ liczbowego wyrażenia warunkowego jest określany w następujący sposób:
I to jest ta część, w której te dwa przypadki są inaczej klasyfikowane.
skutecznie ostateczne
Wersja, do której effectively finalpasuje ta reguła:
W przeciwnym razie ogólna promocja liczbowa ( §5.6 ) jest stosowana do drugiego i trzeciego operandu, a typ wyrażenia warunkowego to promowany typ drugiego i trzeciego operandu.
Jest to takie samo zachowanie, jak gdybyś to zrobił 5 + 'd', tj. W int + charwyniku czego int. Zobacz JLS§5.6
Promocja numeryczna określa promowany typ wszystkich wyrażeń w kontekście liczbowym. Promowany typ jest wybierany w taki sposób, że każde wyrażenie można przekonwertować na promowany typ, aw przypadku operacji arytmetycznej operacja jest zdefiniowana dla wartości typu promowanego. Kolejność wyrażeń w kontekście liczbowym nie ma znaczenia dla promocji liczbowej. Zasady są następujące:
[…]
Następnie do niektórych wyrażeń stosuje się rozszerzającą konwersję pierwotną ( pkt 5.1.2 ) i zwężającą konwersję pierwotną (pkt 5.1.3 ), zgodnie z następującymi regułami:
W kontekście wyboru liczbowego obowiązują następujące reguły:
Jeśli jakiekolwiek wyrażenie jest typu inti nie jest wyrażeniem stałym ( §15.29 ), to promowany typ jest int, a inne wyrażenia, które nie są typu, intsą poddawane rozszerzającej konwersji pierwotnej do int.
Więc wszystko jest promowane inttak, jak ajest intjuż. To wyjaśnia wydajność 97.
finał
Wersja ze finalzmienną jest dopasowana do tej reguły:
Jeśli jeden z operandów jest typu, Tgdzie Tjest byte, shortlub char, a drugi operand jest wyrażeniem stałym ( §15.29 ) typu, intktórego wartość można przedstawić w typie T, to typ wyrażenia warunkowego to T.
Ostatnia zmienna ajest typu inti wyrażeniem stałym (ponieważ jest final). Można to przedstawić jako char, stąd wynik jest typowy char. Na tym kończy się wynik a.
Przykład ciągu
Przykład z równością ciągów opiera się na tej samej podstawowej różnicy, finalzmienne są traktowane jako stałe wyrażenie / zmienna, a effectively finaltak nie jest.
Dlatego w Javie internowanie ciągów opiera się na stałych wyrażeniach
"a" + "b" + "c" == "abc"
jest truerównież (nie używaj tej konstrukcji w prawdziwym kodzie).
Zobacz JLS §3.10.5 :
Ponadto literał łańcuchowy zawsze odnosi się do tego samego wystąpienia klasy String. Dzieje się tak, ponieważ literały łańcuchowe - lub, bardziej ogólnie , łańcuchy, które są wartościami wyrażeń stałych ( §15.29 ) - są „internowane” w celu współużytkowania unikalnych instancji przy użyciu metody String.intern( §12.5 ).
Łatwo przeoczyć, ponieważ mówi głównie o literałach, ale w rzeczywistości dotyczy to również stałych wyrażeń.