Расширения Java-конверсий
Я готовлю сертификацию Java 7 и задаю следующий вопрос.
Byte b = 10
компилируется нормально. Похоже, компилятор сужает int 10 до байт 10, а затем боксирует его. Почему Byte b = new Byte(10)
не будет компилироваться? Почему компилятор не может сузить int 10 до байта 10, как это было в первом случае?
Также как получается, что Long l = new Long(10)
компилируется нормально, но Long l = 10
терпит неудачу?
Я не понимаю, как это работает. Может ли кто-нибудь дать четкое объяснение?
Ответы
Ответ 1
Раздел 5.2 JLS описывает типы конверсий, которые разрешены в контекстах присваивания.
Контексты назначения позволяют использовать одно из следующих значений:
-
преобразование идентичности (§5.1.1)
-
расширяющееся примитивное преобразование (§5.1.2)
-
расширяющееся ссылочное преобразование (§5.1.5)
-
конверсия бокса (§5.1.7) необязательно с последующим расширением ссылочного преобразования
Кроме того,
Кроме того, если выражение является константным выражением (§15.28) типа byte, short, char или int:
-
Сужение примитивного преобразования может быть использовано, если тип переменной является байтом, коротким или char, а значение константного выражения представляется в типе переменной.
-
Сужение примитивного преобразования, за которым следует преобразование бокса, может быть использовано, если тип переменной:
-
Байт и значение константного выражения представляются в байте типа.
-
Короче, а значение константного выражения представляется в типе short.
-
Символ и значение константного выражения представляются в типе char.
Byte b = 10
компилирует ok, потому что 10
является константным выражением и представляется как byte
.
Byte b = new Byte(10)
не будет компилироваться, потому что 10
является литералом int
, а преобразование вызова метода не будет выполнять примитивные суживающие преобразования. Чтобы получить этот вызов конструктора byte
для компиляции, вы можете явно лить 10
в byte
:
Byte b = new Byte( (byte) 10);
Long l = new Long(10)
компилируется, потому что преобразование вызова метода будет выполнять примитивные расширяющие преобразования, в том числе от int
до long
.
Long l = 10
не будет компилироваться, потому что Java не будет специально разрешать расширение конверсии с последующим преобразованием бокса как я обсуждал в недавнем ответе. Чтобы получить это, вы можете использовать литерал long
, поэтому необходим только бокс.
Long l = 10L;
Ответ 2
Основные правила:
- вы не можете конвертировать-и-autobox за один шаг (JLS 5.1.7 определяет конверсии бокса и не включает в себя конвертирование и автобокс типа, поэтому они не разрешены).
- вы не можете неявно сузить тип
Эти правила объясняют, почему Long l = 10
не работает, а также new Byte(10)
. Первый потребовал бы, чтобы int literal 10 расширялся до long
, а затем был помещен в коробку, что запрещено. (Точнее, для этого потребовалось бы преобразование от int
до long
, которое JLS 5.1.7 не определяет.) Второй потребовал бы, чтобы int literal 10 неявно суживался до byte
, который isn ' t.
Но есть исключения из правила. Byte b = 10
явно разрешено JLS 5.2:
Кроме того, если выражение является константным выражением (§15.28) типа byte
, short
, char
или int
:
- Сужение примитивного преобразования, за которым следует преобразование бокса, может быть использовано, если тип переменной:
-
byte
и значение константного выражения представляется в типе byte
.
(некоторые несущественные части опущены)
Наконец, new Long(10)
работает, потому что int literal 10 может автоматически расширяться до длинного 10L.
Ответ 3
10 - целочисленный литерал, вы должны его перетащить, чтобы передать его в конструктор байтов. Там, к сожалению, нет байтового литерала, чтобы удалить листинг.
И как получилось, что Long l = new Long (10) компилируется нормально, но Long l = 10 не удается?
Потому что 10, целое число, может вписаться в длинный без проблем. Целое число не может вписываться в байтовое число, поэтому в этом случае необходимо сделать бросок (расширение преобразования).
Этот листинг также является временем компиляции, так как это также расширяющееся преобразование. Откроем раздел 5.1.5 в JLS:
Расширение ссылочных преобразований никогда не требует специального действия во время выполнения и, следовательно, никогда не генерирует исключение во время выполнения. Они состоят просто в том, чтобы ссылаться на ссылку как на какой-то другой тип способом, который может быть доказан правильно во время компиляции.
Ответ 4
Конструктор байтов принимает либо байтовый, либо строковый тип. См. this
Конструктор для Long занимает много аргументов. Поскольку long может принимать целое число, он позволяет его в конструкторе.
Ответ 5
Я думаю, у меня есть решение для вашей проблемы...
//constructor for Byte class
Byte(byte value){
}
Существует два правила преобразования java-типа
- Оба типа совместимы
- Тип адресата больше, чем тип источника
Теперь в вашем случае вы пытаетесь преобразовать int в байт, который против нашего второго правила....
но ниже - решение
Byte b = new Byte((byte)10);
Теперь поговорим о вашей второй проблеме...
Long x = 10;//incompatible type
Это вопрос автобоксинга...
Теперь, когда все мы знаем, что autoboxing автоматически преобразует примитивный тип в класс оболочки.
Но преобразование не происходит в случае использования autoboxing.... int преобразуется в Целое
байт преобразуется в Байт.
Теперь, когда вы назначаете int примитивный тип Long, он дает вам ошибку несовместимого типа.......
Решение
Long x = (long) 10;//works fine....