Для начала рассмотрим пример переполнения целых чисел на примере примитивного типа byte. Почему byte ? Потому что он занимает 1 байт и проще для восприятия:

System.out.println("[" + Byte.MIN_VALUE +" , " +  Byte.MAX_VALUE + "]");
System.out.println("Byte.SIZE  =   " + Byte.SIZE);
		
byte b = 120;
b += 19;
System.out.println(b);

Вывод на консоль:
[-128 , 127]
Byte.SIZE = 8
-117

Ключевой момент в этом коде, почему вывелось «-117» ?
Числа в ПК хранятся целыми байтами (например примитивный тип byte занимает 1 байт, int — 4 байта). От того, сколько байтов занимает число, зависит количество разрядов числа. Мы знаем, что 1 байт = 8 бит; у примитивного типа byte — 8 разрядов(Byte.SIZE) , у типа int — 4*8 = 32 разряда.
Целые типы (byte, int) знаковые, т.е. могут быть, положительными и отрицательными. ПК не может запомнить минус => изменяется старший бит (1 — число отрицательное, 0 — положительное).
Пример:
Переведем числа 120,19 и -117 в двоичную систему:
120(10) = 0111 1000
19(10) = 0001 0011
-117(10)= 1000 1011

Т.к. у нас старший бит отвечает за знак, то остается 27 — 1 символов для положительной части, и 28 для отрицательной.
Складывая 120 и 19 мы получаем для 8 разрядом число -117

Реклама