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

Тип cast vs literal присваивание

Рассмотрим следующее:

class TypeCast {
    public static void main(String[] args) {
        byte by = 4;   // Compiler casts int literal to byte
        int in = 4;
        byte byt = in; // Compilation Error: compiler can not cast automatically. WHY?
    }
}

Я знаю, что компилятор может сузить в случае литерального назначения. Но он не может сделать то же самое, когда присваивание включает переменную вместо литерала. Почему?

EDIT: Я думаю, что большинство людей не могли понять, что я пытался спросить. Речь идет не о назначении "вне диапазона" значения о назначении "in-range" значения на byte, и пусть компилятор позаботится о сужении. Совершенно очевидно, что "байт" не сможет обработать значение диапазона, и потребует явного преобразования (и это не я хочу знать).

Указанное значение попадает в диапазон byte, в чем разница между int литеральным назначением на byte и int присвоение переменной типа byte?

4b9b3361

Ответ 1

Потому что в вашем коде вы можете изменить значение переменной. Поэтому не разрешается присваивать переменную int байту, но если вы объявите переменную int как final, она позволит попробовать следующее:

 public class Test {
    public static void main(String[] args) {
       final int i = 10;
       byte by = i;
    }
 }

Это означает, что 10 находится в диапазоне байтов, поэтому все нормально, но если вы пишете

public class Test {
   public static void main(String[] args) {
      final int i = 10000;
      byte by = i;
   }
 }

он даст вам ошибку, потому что 10000 не находится в диапазоне байтов.

Ответ 2

Основная причина, IMHO, заключается в том, что такой код (который на самом деле не компилируется)

  int in = ...   // what if in == 1234?;
  byte byt = in; // then byt == -46. Can you expect this?

является опасным из-за потенциального переполнения (int 1234 становится байтом -46). Однако

  byte byt = 4; 

безопасен, поскольку незаконный (переполненный) код, например

  byte byt = 1234; // doesn't compile   

приведет к ошибке времени компиляции. Вы можете настаивать, однако:

  // I'm warned about the overflow, but do as I command...
  byte byt = (byte) 1234; // -46

или

  int in = ...
  byte byt = (byte) in; // I know what I'm doing! Cast it, please 

Ответ 3

Поскольку назначение int на byte вообще не имеет смысла; компилятор не должен выполнять этот вид утверждения.

Причина, по которой компилятор соглашается присвоить значение целочисленного значения байтовой переменной, заключается в том, что он может (и делает) проверять это присвоение во время компиляции, поэтому он полностью безопасен и на самом деле не требует какого-либо "приведения" в все. Если присваивание недействительно, компилятор завершится с ошибкой:

bash$ qjava 'byte b = 128;'
...\QJava.java:4: error: incompatible types: possible lossy conversion from int to byte
    byte b = 128;
             ^
1 error

Ответ 4

byte by = 4 - частный случай. Не существует никакого "приведения", так как допустимы только целочисленные значения, находящиеся в пределах байта диапазона от -128 до 127...

Попробуйте использовать значение вне этого диапазона, и вы получите ту же ошибку

byte small = -128;    // <== OK
byte big = 127;       // <== OK
byte tooSmall = -129; // <== error: Type mismatch: cannot convert from int to byte
byte tooBig = 128;    // <== error: Type mismatch: cannot convert from int to byte

Ответ 5

Ваш байт может представлять только -128 <= X <= 127.

Байт имеет 8 бит. Где первый бит - знак, 0 (положительный) или 1 (отрицательный).

Для положительных остальных семи бит представляют двоичное число.

Ноль равен 00000000. 127 - 01111111.

Для негативов он использует систему два дополнения.

С двумя дополнениями 10000000 представляют -128 и не имеют другого нуля.

Ответ 6

Если С# включил тип байтового литерала и определил логические операторы (Byte | Byte), (Byte ^ Byte), (Byte и Int64), (Int64 и Byte), (Byte и UInt64) и (UInt64 и Byte) для получения результатов байт при заданных указанных операндах, тогда язык может разумно потребовать, чтобы код, который хочет что-то хранить в Byte, должен использовать выражение типа Byte. Однако создатели языка предположили, что преимущества добавления реальной поддержки типов короче, чем Int32, были недостаточными для оправдания стоимости, и поэтому у нее очень мало видов выражений, которые дают что-либо меньшее, чем Int32.

Чтобы учесть, что назначение буквенных значений для коротких переменных чрезвычайно распространено, поскольку у С# нет другого разумного способа обработки таких вещей, язык позволяет целочисленным константам в диапазоне от 0 до 255 неявно преобразовывать в Byte. Ничего в конструкции системы типов, которая подразумевала бы это поведение - это в основном kludge для обработки наиболее распространенных ситуаций, когда отсутствие надлежащей поддержки типа байта в противном случае представляло бы серьезную досаду.