Продвижение примитивных типов


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

Версия метода primitive long работает без ошибок, в то время как версия класса-оболочки Long терпит неудачу. Это происходит потому, что литерал int в операторе return сначала будет переведен в более широкий примитивный тип (например, long), а затем в соответствующий класс обертки Integer и так далее. Поскольку Integer не является подклассом Long, компилятор выдает ошибку.

Но почему версия класса-оболочки Byte работает без ошибок? Что именно делает компилятор на этом этапе?

long getPrimitiveLong() {
    return 12; // valid
}

Long getWrapperLong() {
    return 12; // Error: type mismatch
}

Byte getWrapperByte() {
    return 12; // valid
}
4 3

4 ответа:

Версия с Byte работает через некоторую магию компилятора.

В отличие от long числовых литералов, которые могут быть построены с помощью L, например, 12L, нет такой вещи, как byte литерал. Вот почему компилятор Java обрабатывает числовые литералы, которые помещаются в байт, как литералы byte. Следовательно, 12 в вашем последнем примере рассматривается константа типа byte.

Спецификация языка Java предлагает описание этого преобразования в разделе 5.2:

Можно использовать сужающее примитивное преобразование с последующим боксерским преобразованием если тип переменной:

  • Byte и значение постоянного выражения представимо в виде byte.
  • Short и значение постоянного выражения представимо в виде short.
  • Character и значение постоянного выражения представимо в виде char.

Это потому, что Java позволяет 1 преобразование или Автобоксинг, не более.

Java может делать все это:

int i = 5;
double d = i;
long l = i;

Или autobox:

Integer i = 5;
Long l = 5L;
Double d = 5.0;

Преобразование дважды дает Java трудное время.

Число типа 12 по умолчанию компилятором рассматривается как int, поэтому Ошибка

Чтобы исправить это, вы можете использовать приведение для байта и поместить L после значения переменной long.

Прочитайте следующий пост для получения более подробной информации

Http://javaseeeedu.blogspot.com/2015/12/casting-part-1.html

В качестве короткого ответа-попробуйте заменить 12 на 128 (байт находится в диапазоне от -128 до 127). Он не будет компилироваться, верно? Результатом здесь является то, что компилятор знает о границах байтов.

Для глубокого ответа вы можете сделать глубокое погружение в OpenJDK.