Почему в Java при переключении через оболочку Integer регистр 'char' не компилируется, но компиляция в порядке, когда коммутатор находится над байтом? - PullRequest
18 голосов
/ 05 октября 2019

Не компилируется:

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

Компилируется ОК:

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

1 Ответ

19 голосов
/ 05 октября 2019

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

Прежде всего, JLS 14.11 говорит следующее о switch операторах:

"Каждая константа регистра, связанная с оператором switch, должна быть совместима с присваиванием с типом выражения выражения оператора 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)
  • anраспаковка конверсии с последующим расширением примитивного преобразования. "

Чтобы перейти от 'a' к Integer, мынам нужно 1 расширить значение char до int, а затем int до Integer. Но если вы посмотрите на комбинации разрешенных преобразований, вы не сможете выполнить расширенное преобразование примитивов с последующим преобразованием в бокс.

Следовательно, 'a' в Integer недопустимо. Это объясняет ошибку компиляции в первом случае.

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

"Кроме того, если выражение является константным выражением ( §15.28 ) типаbyte, short, char или int:

  • Может использоваться сужающее примитивное преобразование, если переменная имеет тип byte, short или char, и значениеконстантного выражения представимо в типе переменной.

  • Может использоваться сужающее примитивное преобразование с последующим преобразованием в бокс, если переменная имеет тип Byte, Short или Character, а значение константного выражения может быть представлено в типе byte, short или char соответственно. "

Второй из них относится к 'a' к Byte, потому что:

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

Это объясняет, почему существует no ошибка компиляции во втором примере.


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

...