Java ничего не делает с целочисленным переполнением ни для типов int, ни для длинных примитивов, и игнорирует переполнение положительными и отрицательными целыми числами.
В этом ответе сначала описывается целочисленное переполнение, дается пример того, как это может произойти даже с промежуточными значениями при вычислении выражений, а затем даются ссылки на ресурсы, которые предоставляют подробные методы предотвращения и обнаружения целочисленного переполнения.
Целочисленная арифметика и выражения, приводящие к неожиданному или необнаруженному переполнению, являются распространенной ошибкой программирования.Неожиданное или необнаруженное целочисленное переполнение также является хорошо известной уязвимостью, которую можно использовать, особенно когда она затрагивает объекты массива, стека и списка.
Переполнение может происходить в положительном или отрицательном направлении, где положительное или отрицательное значение будет выше максимального или минимального значения для рассматриваемого типа примитива.Переполнение может произойти в промежуточном значении во время выражения или оценки операции и повлиять на результат выражения или операции, где ожидается, что окончательное значение будет в пределах диапазона.
Иногда отрицательное переполнение ошибочно называют недостаточным.Underflow - это то, что происходит, когда значение будет ближе к нулю, чем позволяет представление.Недостаток происходит в целочисленной арифметике и ожидается.Потеря целочисленного значения происходит, когда целочисленная оценка будет между -1 и 0 или 0 и 1. То, что будет дробным результатом, усекается до 0. Это нормально и ожидается с целочисленной арифметикой и не считается ошибкой.Однако это может привести к исключению кода.Одним из примеров является исключение «ArithmeticException: / by zero», если результат целочисленного занижения используется в качестве делителя в выражении.
Рассмотрим следующий код:
int bigValue = Integer.MAX_VALUE;
int x = bigValue * 2 / 5;
int y = bigValue / x;
, в результате которого x присваивается 0, а последующая оценка bigValue / x вызывает исключение «ArithmeticException: / by zero» (т.е. делится нанулю), вместо y присваивается значение 2.
Ожидаемый результат для x будет 858,993,458, что меньше максимального значения int в 2,147,483,647.Однако промежуточный результат оценки Integer.MAX_Value * 2 будет равен 4 294 967 294, что превышает максимальное значение int и равно -2 в соответствии с целочисленными представлениями дополнения 2s.Последующая оценка -2 / 5 оценивается в 0, что присваивается х.
Перестановка выражения для вычисления x в выражение, которое при вычислении делит перед умножением следующий код:
int bigValue = Integer.MAX_VALUE;
int x = bigValue / 5 * 2;
int y = bigValue / x;
приводит к тому, что x назначается 858,993,458, а y назначается 2, чтоожидается.
Промежуточный результат от bigValue / 5 равен 429 496 729, что не превышает максимального значения для целого числа.Последующая оценка 429 496 729 * 2 не превышает максимальное значение для int, и ожидаемый результат присваивается x.Оценка для y тогда не делится на ноль.Оценки для x и y работают как положено.
Целочисленные значения Java хранятся как и ведут себя в соответствии с дополнением 2s к знаковым целочисленным представлениям.Когда результирующее значение будет больше или меньше, чем максимальное или минимальное целочисленные значения, вместо этого получается целочисленное значение дополнения 2.В ситуациях, специально не предназначенных для использования поведения дополнения 2s, которое является наиболее обычными целочисленными арифметическими ситуациями, результирующее значение дополнения 2s вызовет логику программирования или ошибку вычисления, как было показано в примере выше.Отличная статья в Википедии описывает двоичные целые числа с комплиментами 2s здесь: Дополнение к двум - Википедия
Существуют методы, позволяющие избежать непреднамеренного целочисленного переполнения.Techinques могут быть классифицированы как использование предварительного тестирования, апкастинга и BigInteger.
Предварительное тестирование включает проверку значений, входящих в арифметическую операцию или выражение, чтобы убедиться, что переполнение этими значениями не произойдет.Программирование и проектирование должны создать тестирование, которое обеспечит, что входные значения не вызовут переполнения, а затем определит, что делать, если произойдут входные значения, которые вызовут переполнение.
Upcasting включает использование более крупного примитивного типа для выполнения арифметической операции или выражения, а затем определение, превышает ли результирующее значение максимальное или минимальное значения для целого числа.Даже при использовании восходящего вещания все еще возможно, что значение или некоторое промежуточное значение в операции или выражении будут выходить за пределы максимального или минимального значения для типа восходящего вещания и вызывать переполнение, которое также не будет обнаружено и приведет к неожиданным и нежелательным результатам.Посредством анализа или предварительных условий может быть возможно предотвратить переполнение с помощью апкастинга, когда предотвращение без апскейтинга невозможно или практически невозможно.Если рассматриваемые целые числа уже являются длинными примитивными типами, то в Java примитивные типы невозможны.
Метод BigInteger включает использование BigInteger для арифметической операции или выражения с использованием библиотечных методов, использующих BigInteger.BigInteger не переполняется.Он будет использовать всю доступную память, если это необходимо.Его арифметические методы обычно лишь немного менее эффективны, чем целочисленные операции.Все еще возможно, что результат, использующий BigInteger, может быть выше максимального или минимального значения для целого числа, однако переполнение не произойдет в арифметике, приводящей к результату.Программирование и проектирование все еще должны определить, что делать, если результат BigInteger превышает максимальные или минимальные значения для желаемого примитивного типа результата, например, int или long.
Программа CERT Института разработки программного обеспечения Карнеги-Меллона и Oracle разработали набор стандартов для безопасного программирования на Java.В стандарты включены методы предотвращения и обнаружения целочисленного переполнения.Стандарт опубликован в виде свободно доступного онлайн-ресурса здесь: Стандарт безопасного кодирования Oracle CERT для Java
Раздел стандарта, который описывает и содержит практические примеры методов кодирования для предотвращения или обнаружения целочисленного переполненияздесь: NUM00-J.Обнаружение или предотвращение целочисленного переполнения
Книжная форма и PDF-форма CERT Oracle Secure Coding Standard для Java также доступны.