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

Расширения 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 терпит неудачу?

Я не понимаю, как это работает. Может ли кто-нибудь дать четкое объяснение?

4b9b3361

Ответ 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....