Кастинг 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) требует расширения примитивного преобразования и сужения примитивного преобразования, однако этот бросок также разрешен компиляторами.
Может кто-нибудь просветить меня?
Изменить:, так как я просил об этом, я отправил
Ответы
Ответ 1
Я думаю, что вы правы, компиляторы правы, а спецификация ошибочна....
Это компилируется: (Object)45
, и это не так: (Long)45
Единственный способ понять поведение компиляторов (в том числе Intellij, я использую), - это преобразование Casting Conversion, чтобы согласовать с Conversion Conversion и Invocation Conversion:
плюс
- расширение и сужение примитивной конвекции
В спецификации говорилось, что "конверсии кастинга более инклюзивные, чем преобразования присваивания или обращения к методу: приведение может делать любое разрешенное преобразование, отличное от преобразования строк или преобразования захвата"
Ответ 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;
Вы считаете, что любой из них удивляет? Ваш оригинальный пример не выглядит иначе; он просто возвращает промежуточные переменные.