Тип 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
?
Ответы
Ответ 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 для обработки наиболее распространенных ситуаций, когда отсутствие надлежащей поддержки типа байта в противном случае представляло бы серьезную досаду.