Подтвердить что ты не робот

Кастинг Java: неправильный компилятор или неправильная формулировка языка, или я ошибаюсь?

Я читал спецификацию Java Language Spec, 3-е издание и нашел то, что, по моему мнению, является расхождением между спецификацией и реализацией компилятора javac. Те же расхождения существуют в компиляторе Eclipse.

Раздел 15.16 рассказывает о литых выражениях. В нем говорится, что это должна быть ошибка времени компиляции, если тип аргумента не может быть преобразован в тип каста посредством преобразования каста (раздел 5.5):

Это ошибка времени компиляции, если тип экземпляра типа компиляции никогда не может быть применен к типу, указанному оператором литья в соответствии с правилами преобразования кастования (§5.5). В противном случае во время выполнения значение операнда преобразуется (при необходимости) путем преобразования преобразования в тип, заданный оператором литья.

Раздел 5.5 рассказывает о преобразовании кастомизации. Он дает список типов конверсий, которые разрешены. В частности, отсутствующим в списке является "преобразование распаковки с последующим расширением/сужением примитивного преобразования". Однако точная последовательность преобразований, по-видимому, разрешена компилятором javac (а также компилятором Eclipse). Например:

long l = (long) Integer.valueOf(45);

... компилируется просто отлично. (Проблемное литье - это приведение к long, аргумент имеет тип java.lang.Integer, поэтому для преобразования требуется unboxing to int, за которым следует расширение примитивного преобразования).

Аналогично, в соответствии с JLS нельзя отличать от byte до char, потому что это (согласно 5.1.4) требует расширения примитивного преобразования и сужения примитивного преобразования, однако этот бросок также разрешен компиляторами.

Может кто-нибудь просветить меня?

Изменить:, так как я просил об этом, я отправил

4b9b3361

Ответ 1

Я думаю, что вы правы, компиляторы правы, а спецификация ошибочна....

Это компилируется: (Object)45, и это не так: (Long)45

Единственный способ понять поведение компиляторов (в том числе Intellij, я использую), - это преобразование Casting Conversion, чтобы согласовать с Conversion Conversion и Invocation Conversion:

  • конверсия бокса (§5.1.7) необязательно с последующим расширением ссылочное преобразование

  • преобразование для распаковки (п. 5.1.8) необязательно с последующим расширением примитивное преобразование.

плюс

  • расширение и сужение примитивной конвекции

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

Ответ 2

По моему показанию, данный класс от int до long разрешен в этом разделе:

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

Преобразование int в long является расширением примитивного преобразования.

Это просто оставляет преобразование от Integer до int, которое помещается последней маркой:

преобразование распаковки

Конечно, приведение в long даже не нужно в этом примере.

Рассмотрим следующие четыре определения:

final Integer io = Integer.valueOf(45);
final int i = io;
final long l1 = (long)i;
final long l2 = i;

Вы считаете, что любой из них удивляет? Ваш оригинальный пример не выглядит иначе; он просто возвращает промежуточные переменные.