Дивна потрійна поведінка Java при призначенні значення. Що робить Java за лаштунками, щоб це сталося?


10

Кілька днів тому я зіткнувся із захоплюючим сценарієм, що не зміг знайти жодної документації про те, як і чому Java дозволяє зробити таке. (Цей фрагмент - це просто спрощена форма помилки.)

    @Test
    public void test() {
      boolean bool = false;
      Integer intVal = Integer.valueOf(5);
      Long longVal = null;
      Long result = bool ? intVal : longVal;

      System.out.println(" > " + result);
   }

у фрагменті вище:

якщо bool = true, то ви отримуєте значення '5';

але якщо bool = false, то ви отримуєте нульовий виняток вказівника при спробі оцінити потрійну операцію. НЕ заяву про друк.


Щоб виправити це, я просто змінюю "результат" на

Long result = bool ? Long.valueOf(intVal) : longVal;

Це призведе до потрібної мені поведінки:

якщо bool = true, то ви отримуєте значення '5';

але якщо bool = false, то ви отримуєте 'null'


Тепер цікавою частиною є те, що якщо ви розділите це на звичайний оператор if / else, то java НЕ дозволяє вам компілювати

longVal = intVal; 

але це не сприймає це через термінального оператора. Отже, що робить Java, щоб зробити її нульовою точкою в оригінальному фрагменті?

(java 11)

Відповіді:


10

Коли ви це зробите:

Long result = bool ? intVal : longVal

Цей вираз повертає a, longа коли boolпомилковий, він намагається розв’язати nullзначення Long, щоб підходити до resultзмінної та кидає NPE.

Коли ви це зробите:

Long result = bool ? Long.valueOf(intVal) : longVal

Цей вираз уже повертається, Longтоді немає необхідності в розпакуванні, і nullзначення успішно присвоюється resultзмінній.

Довідка:

Як було обговорено в розділі коментарів, щоб краще зрозуміти, чому це відбувається, перегляньте наступні розділи JLS:


Я здивований, що ви відрізняєтесь довідковою таблицею 15.25 від A до E, де "зрозуміло", що Integer / Long приводить до bnp (Integer, Long).
мат

Хороша відповідь. Як правило, коли я абсолютно не маю уявлення, що відбувається всередині, я рекомендую подивитися в складеному байт-коді, який майже точно розкриває те, що описано. Принаймні, витягуючи фрагмент мінімального коду, це більш-менш питання навчання, як його читати та розуміти.
Ян Хелд

Як говориться в розділі 5.6.2 JLS : "Якщо будь-який операнд є еталонним типом, він піддається розгорнутому перетворенню"; тоді "Застосовується розширювальне примітивне перетворення (§5.1.2) [..]"
Дієго Магдалено
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.