Перш за все, мова йде лише про локальні змінні . Фактично остаточний не застосовується до полів. Це важливо, оскільки семантика finalполів дуже чітка і піддається жорсткій оптимізації компілятора та обіцянкам моделі пам'яті, див. $ 17.5.1 щодо семантики кінцевих полів.
На поверхневому рівні finalта effectively finalдля локальних змінних дійсно однакові. Однак JLS чітко розмежовує їх, що насправді має широкий спектр ефектів у таких особливих ситуаціях.
Приміщення
З JLS§4.12.4 про finalзмінні:
Мінлива константа є finalзмінною примітивного типу або типу String , що інстанціюється з постійним виразом ( §15.29 ). Чи є змінна постійною змінною, чи ні, це може мати наслідки щодо ініціалізації класу ( §12.4.1 ), бінарної сумісності ( §13.1 ), доступності ( §14.22 ) та певного призначення ( §16.1.1 ).
Оскільки intпримітивна, змінна aє такою постійною змінною .
Далі, з тієї ж глави про effectively final:
Деякі змінні, які не оголошені остаточними, натомість вважаються фактично остаточними: ...
Таким чином , з образом це сформульовано, то ясно , що в іншому прикладі, aце НЕ вважається постійної змінної, так як це НЕ є остаточним , але тільки ефективно остаточним.
Поведінка
Тепер, коли ми маємо різницю, давайте подивимося, що відбувається і чому результат виходить інший.
Ви використовуєте умовний оператор ? :тут, тому ми повинні перевірити його визначення. З JLS§15.25 :
Існує три типи умовних виразів, класифікованих відповідно до виразів другого та третього операндів: логічні умовні вирази , числові умовні вирази та посилальні умовні вирази .
У цьому випадку ми говоримо про числові умовні вирази з JLS§15.25.2 :
Тип числового умовного виразу визначається наступним чином:
І це частина, де ці два випадки класифікуються по-різному.
фактично остаточний
Версія, яка effectively finalвідповідає цьому правилу:
В іншому випадку загальне числове просування ( §5.6 ) застосовується до другого та третього операндів, а тип умовного виразу - це підвищений тип другого та третього операндів.
Це така сама поведінка, як якщо б ви робили 5 + 'd', тобто int + char, що призводить до int. Див. JLS§5.6
Числове просування визначає тип просування всіх виразів у числовому контексті. Тип, що рекламується, вибирається таким чином, що кожен вираз може бути перетворений у тип, що рекламується, і, у випадку арифметичної операції, операція визначена для значень рекламного типу. Порядок виразів у числовому контексті не є значущим для числового просування. Правила такі:
[...]
Далі, розширення примітивного перетворення ( §5.1.2 ) та звуження примітивного перетворення ( §5.1.3 ) застосовуються до деяких виразів, згідно з наступними правилами:
У контексті числового вибору застосовуються такі правила:
Якщо будь-який вираз має тип intі не є постійним виразом ( §15.29 ), тоді промотований тип є int, а інші вирази, що не мають типу, intзазнають розширення примітивного перетворення в int.
Отже, все просувається до того int, aщо intвже є. Це пояснює результат 97.
остаточний
Версія зі finalзмінною відповідає цьому правилу:
Якщо один з операндів має типу , Tде Tзнаходиться byte, shortабо char, а інший операндом є постійним виразом ( §15.29 ) типу int, значення якого представимо в типі T, то тип умовного виразу T.
Кінцева змінна aмає тип intі постійний вираз (оскільки вона є final). Це можна представити як char, отже, результат є типовим char. На цьому результат закінчується a.
Приклад рядка
Приклад з рівністю рядків базується на тій же різниці ядра, finalзмінні трактуються як константний вираз / змінна, і effectively finalце не так.
У Java розпізнавання рядків базується на константних виразах, отже
"a" + "b" + "c" == "abc"
є trueтакож (не використовуйте цю конструкцію в реальному коді).
Див. JLS§3.10.5 :
Більше того, строковий літерал завжди посилається на один і той же екземпляр класу String. Це пояснюється тим, що рядкові літерали - або, загальніше , рядки, що є значеннями константних виразів ( §15.29 ) - "інтернуються" , щоб спільно використовувати унікальні екземпляри, використовуючи метод String.intern( §12.5 ).
Легко не помітити, оскільки мова йде переважно про літерали, але насправді це стосується і постійних виразів.