Чому в перемиканні Java через обгортку Integer "не" справа "char" не компілюється, а компіляція в порядку, коли перемикач переходить на байт?


18

Не компілюється:

void test(Integer x) {
      switch (x) {
          case 'a':
      }
}

Компілює ОК:

void test(Byte x) {
      switch(x) {
          case 'a':
      }
}

1
Ціле число - 4 байти, а знаки - 2 байти. Тож у першому випадку, незалежно від того, який символ ви пишете, він менший за ціле число. Однак у другому випадку символ, який ви написали, може бути більшим за максимальний байт, завдяки чому цей випадок ніколи не виконується.
Ярослав Павлак

Це пояснення невірно. Дійсно, у другому прикладі код у 'a'справі буде виконуватися у випадку, що xє байтом 97. (Спробуйте, якщо ви мені не вірите.) Для справжнього пояснення дивіться мою відповідь.
Stephen C

Відповіді:


19

Причини досить складні, але вони все в деталях ( дрібний шрифт , якщо ви хочете) з специфікації мови Java.

По-перше, JLS 14.11 говорить про наступні switchтвердження:

"Кожна константа випадку, пов'язана з оператором перемикання, повинна бути призначенням, сумісним з типом вираження оператора перемикання ( §5.2 )."

Це означає , що 'a'має бути віднесено до Integerі Byte відповідно.

Але це не здається правильно:

  • Ви можете подумати, що оскільки це 'a' має бути віднесено до присвоєння, Integerоскільки char-> intє законним. (Будь-яке charзначення впишеться в int.)

  • Ви думаєте, що оскільки 'a' НЕ слід привласнювати до присвоєння, Byteоскільки char-> byte це не є законним. (Більшість charзначень не вписуються в байт.)

Насправді жодне з них не є правильним. Щоб зрозуміти чому, нам потрібно прочитати, що насправді JLS 5.2 стосується того, що дозволено в контекстах призначення.

"Контексти присвоєння дозволяють використовувати одне з наступного :

  • перетворення ідентичності (§5.1.1)
  • розширювальне примітивне перетворення (§5.1.2)
  • розширення еталонного перетворення (§5.1.5)
  • розширення конверсії посилань з подальшим розгортанням
  • конверсія розширення посилань з наступною конверсією розпакування, а потім розширення примітивного перетворення
  • перетворення боксу (§5.1.7)
  • перетворення боксу з подальшим розширенням конверсії
  • конверсія для розпакування (§5.1.8)
  • конверсія для розгортання з подальшим розширенням примітивної конверсії. "

Для того, щоб перейти від 'a'до Integer, нам знадобиться 1 розширити charзначення на intполе тоді, щоб intперейти на Integer. Але якщо ви подивитеся на дозволені комбінації перетворень, ви не можете здійснити розширювальну примітивну конверсію, за якою слід перетворити бокс.

Тому , 'a'щоб Integerне допускається. Це пояснює помилку компіляції у першому випадку.

Можна подумати, що 'a'до Byteвідкидається , тому що спричинить за собою примітивне звужує перетворення ... , який не перебуває у списку взагалі. Насправді літерали - це особливий випадок. JLS 5.2 продовжує говорити наступне.

"Крім того, якщо вираз є постійним виразом ( §15.28 ) типу байта, шрифту, знака або int:

  • Примітивне перетворення, що звужує, може бути використане, якщо змінна має тип байта, короткого чи знаку, а значення постійного вираження є представним у типі змінної.

  • Примітивне перетворення, що супроводжується звуженням, за яким слід перетворення боксу, може бути використане, якщо змінна має тип Byte, Shortабо Character, і значення постійного вираження є представним відповідно в байті типу, короткому або знаку відповідно. "

Другий з них відноситься до 'a'до Byte, тому що:

  • буквений символ - це постійний вираз, і
  • величина 'a'є 97десяткової, який знаходиться в межах діапазону byte( -128з +127).

Це пояснює, чому немає помилки компіляції у другому прикладі.


1 - Ми не можемо боксувати 'a'до , Characterа потім розширити Characterдо , Integerтому що Characterце не Java підтип Integer. Можна використовувати розширювальну перехідну посилання лише тоді, коли тип джерела є підтипом цільового типу.


Чи можемо ми використовуватись intяк тип комутатора? (оскільки char -> intдозволено примітивне розширення, яке дозволено)
AjahnCharles
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.