Java - короткие и литые

У меня есть следующий фрагмент кода.

public static void main(String[] args) {
 short a = 4;
 short b = 5;
 short c = 5 + 4;
 short d = a;
 short e = a + b; // does not compile (expression treated as int)


 short z = 32767;
 short z_ = 32768; // does not compile (out of range)

 test(a);
 test(7); // does not compile (not applicable for arg int)
}

public static void test(short x) { }

Является ли следующее краткое изложение правильным (в отношении только приведенного выше примера с использованием краткого)?

  • прямые инициализации без литья возможны только с использованием литералов или одиночных переменных (если значение находится в диапазоне объявленного типа)
  • если rhs присваивания имеет дело с выражениями с использованием переменных, требуется литье

Но почему именно мне нужно передать аргумент второго вызова метода с учетом предыдущего резюме?

Ответ 1

Это соответствующие разделы JLS:

JLS 5.1.1 Преобразование идентичности

Для любого типа допускается преобразование из типа в тот же тип.

JLS 5.2 Преобразование присваивания

Преобразование присваивания происходит, когда значение выражения присваивается переменной: тип выражения должен быть преобразован в тип переменной. Контексты присваивания позволяют использовать одно из следующего:

  • Преобразование удостоверений
  • [...]

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

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

Вышеупомянутые правила объясняют все следующее:

short a = 4;     // representable constant
short b = 5;     // representable constant
short c = 5 + 4; // representable constant
short d = a;     // identity conversion
short e = a + b; // DOES NOT COMPILE! Result of addition is int

short z  = 32767; // representable constant
short z_ = 32768; // DOES NOT COMPILE! Unrepresentable constant

Как это не компилируется:

test(7); // DOES NOT COMPILE! There no test(int) method!

Это потому, что сужение преобразования с константой определяется только для присвоений; а не для вызова метода, который имеет совершенно разные правила.

JLS 5.3. Конверсия вызова метода

Преобразования вызова метода конкретно не включают неявное сужение целочисленных констант, которое является частью преобразования присваивания. Дизайнеры языка программирования Java считали, что включение этих неявных сужений в конверсии добавит дополнительную сложность перегруженному методу, соответствующему процессу разрешения.

Вместо того, чтобы объяснять, как работает разрешение метода, я просто укажу на Эффективное Java 2nd Edition, пункт 41: разумно используйте перегрузку:

Правила, определяющие, какая перегрузка выбрана, чрезвычайно сложны. Они занимают тридцать три страницы в спецификации языка, и лишь немногие программисты понимают все их тонкости.


См. также

Ответ 2

Результат арифметической операции над значениями short всегда int. test(7) не работает, так как вы не сказали, что 7 имеет тип short. Компилятор здесь должен быть немного умнее.

Ответ 3

"7" в вызове test(7); является int и не будет автоматически преобразован в short.

Он работает, когда вы объявляете и инициализируете значения short, но это особый случай для компилятора. Этот специальный случай не существует для вызовов методов.