Предел int
составляет от -2147483648 до 2147483647.
Если я введу
int i = 2147483648;
затем Eclipse предложит красное подчеркивание под «2147483648».
Но если я сделаю это:
int i = 1024 * 1024 * 1024 * 1024;
это будет компилироваться нормально.
public class Test {
public static void main(String[] args) {
int i = 2147483648; // error
int j = 1024 * 1024 * 1024 * 1024; // no error
}
}
Может быть, это основной вопрос в Java, но я понятия не имею, почему второй вариант не дает ошибок.
2147483648
: этот буквальный смысл не имеет смысла.Ответы:
В этом утверждении нет ничего плохого; Вы просто умножаете 4 числа и присваиваете его целому числу, просто случается переполнение. Это отличается от присвоения одного литерала , который будет проверяться границами во время компиляции.
Это литерал вне пределов, который вызывает ошибку, а не присваивание :
В противоположность этому,
long
литерал будет компилироваться нормально:Следует отметить , что, по сути, результат будет по- прежнему вычисляется во время компиляции , потому что
1024 * 1024 * 1024 * 1024
это выражение константы :будет выглядеть так:
Обратите внимание, что result (
0
) просто загружается и сохраняется, и умножение не происходит.Из JLS §3.10.1 (спасибо @ChrisK за то, что он поднял это в комментариях):
источник
-1 + 1
, это безвредно; но1024^4
это может привести к слепоте людей с совершенно неожиданными результатами, далекими от того, что они ожидают увидеть. Я думаю, что должно быть по крайней мере предупреждение или примечание для пользователя, а не молча игнорировать его.1024 * 1024 * 1024 * 1024
и2147483648
не имеют одинаковое значение в Java.На самом деле,
2147483648
даже не имеет значения (хотя и2147483648L
есть) в Java. Компилятор буквально не знает, что это такое и как его использовать. Так что скулит.1024
является действительным int в Java, и действительное значение,int
умноженное на другое действительное значениеint
, всегда является допустимымint
. Даже если это не то значение, которое вы ожидаете интуитивно ожидать, потому что вычисления будут переполнены.пример
Рассмотрим следующий пример кода:
Вы ожидаете, что это приведет к ошибке компиляции? Это становится немного более скользким теперь.
Что если мы поместим цикл с 3 итерациями и умножим на цикл?
Компилятору разрешено оптимизировать, но он не может изменить поведение программы, пока он это делает.
Некоторая информация о том, как на самом деле обрабатывается этот случай:
В Java и многих других языках целые числа будут состоять из фиксированного числа битов. Вычисления, которые не соответствуют данному количеству битов, будут переполнены ; вычисление в основном выполняется по модулю 2 ^ 32 в Java, после чего значение преобразуется обратно в подписанном целое.
Другие языки или API используют динамическое число битов (
BigInteger
в Java), вызывают исключение или устанавливают магическое значение, например not-a-number.источник
2147483648
НЕ ДАЖЕ ЗНАЧЕНИЕ (хотя и2147483648L
есть)» действительно укрепило мысль, которую @arshajii пытался сделать.1024 * 1024 * 1024 * 1024
обрабатывается, я действительно хотел подчеркнуть, что это не то же самое, что писать2147473648
. Есть много способов (и вы перечислили несколько), что язык потенциально может с этим справиться. Это разумно разделено и полезно. Так что я оставлю это. Много информации становится все более необходимым, когда у вас есть высокий рейтинг ответа на популярный вопрос.Поведение, которое вы предлагаете, то есть создание диагностического сообщения, когда вычисление выдает значение, которое больше, чем наибольшее значение, которое может быть сохранено в целом числе, - это функция . Чтобы использовать любую функцию, ее необходимо продумать, считать хорошей идеей, спроектировать, указать, внедрить, протестировать, документировать и отправить пользователям.
Для Java одна или несколько вещей из этого списка не произошли, и поэтому у вас нет возможности. Я не знаю, какой из них; вам придется спросить Java-дизайнера.
Для C # все это произошло - около четырнадцати лет назад, и поэтому соответствующая программа на C # вызвала ошибку, начиная с C # 1.0.
источник
В дополнение к ответу Аршаджи я хочу показать еще одну вещь:
Не присваивание вызывает ошибку, а просто использование литерала . Когда вы пытаетесь
Вы также заметите, что это также вызывает ошибку компиляции, так как правая часть все еще является
int
литеральной и находится вне диапазона.Таким образом, операции с
int
-values (включая присваивания) могут переполняться без ошибки компиляции (и без ошибки времени выполнения), но компилятор просто не может обработать эти слишком большие литералы.источник
A: Потому что это не ошибка.
Фон: умножение
1024 * 1024 * 1024 * 1024
приведет к переполнению. Переполнение очень часто является ошибкой. В случае переполнения разные языки программирования ведут себя по-разному. Например, C и C ++ называют это «неопределенным поведением» для целых чисел со знаком, а поведение определяется целыми числами без знака (взять математический результат, сложить,UINT_MAX + 1
если результат отрицательный, вычесть,UINT_MAX + 1
если результат больше, чемUINT_MAX
).В случае Java, если результат операции со
int
значениями не находится в допустимом диапазоне, концептуально Java добавляет или вычитает 2 ^ 32, пока результат не окажется в допустимом диапазоне. Так что утверждение абсолютно законно и не по ошибке. Это просто не дает результата, на который вы, возможно, надеялись.Вы можете с уверенностью утверждать, полезно ли такое поведение, и должен ли компилятор предупреждать вас. Я бы лично сказал, что предупреждение было бы очень полезно, но ошибка была бы неправильной, так как это допустимая Java.
источник