Decembrist blog.

Всё не так с целочисленными примитивами в java

Word count: 927 / Reading time: 6 min
2018/07/01 Share

В языке Java 8 примитивных типов

  • Целочисленные byte, short, int, long (отчасти/полностью char)
  • Вещественные double и float
  • Булевый boolean соответственно

Если, скажем, ты будешь выполнять простейшие операции вроде сумма разница (+/-) или любыми другими
с 2мя переменными одного типа, то результирующий тип более или менее предсказуем.

К примеру:

int a = 2;
int b =3;

Результирующий тип операции a + b будет int

Как это проверить

(Если ты пока не сильно понимаешь в ООП то можешь скопипастить вот такой класс для проверки типов )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Type {

final static private String MESSAGE_TEMPLATE = "This is %s type";

void check(int a) {
System.out.println(String.format(MESSAGE_TEMPLATE, "int"));
}

void check(long a) {
System.out.println(String.format(MESSAGE_TEMPLATE, "long"));
}

void check(short a) {
System.out.println(String.format(MESSAGE_TEMPLATE, "short"));
}

void check(byte a) {
System.out.println(String.format(MESSAGE_TEMPLATE, "byte"));
}

}

Объяснение кода класса выходит за границы данного видео, но если вкратце, то вызов метода
check у экземпляра этого класса с примитивным целочисленным параметром будет выводить
текст "This is ${название типа} type"

проверим:

int a = 2; //объявлена переменная примитивного типа int
final Type type = new Type(); //создаётся экземпляр класса Type (код выше)
type.check(a); //проверяем тип

Вывод: This is int type

Пока всё логично:
Сложим-ка теперь 2 переменных типа int

1
2
3
4
int a = 2; //объявлена первая переменная примитивного типа int
int b = 2; //объявлена вторая переменная примитивного типа int
final Type type = new Type(); //создаётся экземпляр класса Type (код выше)
type.check(a + b); //проверяем тип

Вывод This is int type

Пока всё логично.

Но что будет если сложить 2 примитива разных типов:

1
2
3
4
long a = 2; //объявлена первая переменная примитивного типа long
int b = 2; //объявлена вторая переменная примитивного типа int
final Type type = new Type(); //создаётся экземпляр класса Type (код выше)
type.check(a + b); //проверяется тип

Какой вывод? А?

Правильный ответ This is long type лонг

Почему?

Возможно ты не знаешь но типы byte, short, int, long отличаются вместимостью
(что означает что в памяти они занимают разное количество байтиков)

byte - 1 байтик - Диапазон значений от -128 до 127 включительно,

short - 2 байтиков - Диапазон значений от -32768 до 32767 включительно,

int - 4 байтиков - Диапазон значений от -2147483648 до 2147483647 включительно,

long - 8 байтиков - Диапазон значений от -2 в 63 степени до 2 в 63 степени - 1 включительно

cоответственно вмещаемый диапазон значений тоже увеличивается с количеством байтов
ты можешь увидеть конкретные числа в даннной таблице

java конвертирует оба операнда в более широкий тип изза указаных выше причин
таким образом фактически складываются 2 типа лонг и результатом само собой будет тип лонг

а теперь поглядим что будет если указанные диапазоны значений переполнить
для типа int

1
2
int intMax = 2147483647; //запись в переменную максимально возможного числа типа int
System.out.println(intMax + 1);

вывод казалось бы должен быть 2147483648
но вывод -2147483648

Так как тип int не вмещает больше 4 байт или числа 2147483647 следующее число в последовательности
это минимально возможное значение диапазона типа int
таким образом число будет вращаться по кругу вновь при каждом переполнении возвращаться к минимальному
и наоборот соответственно, что может ызывать ошибку в твоих вычислениях

Если ты предполагаешь что число может быть выше возможного максимального значения используй более широкий тип
Минимальное и максимальное значения типа int можно получить через статический метод Integer.MIN_VALUE
и Integer.MAX_VALUE соответственно int intMax = Integer.MAX_VALUE;

типы Byte Short и Long работают аналогично

Таким образом стоит запомнить что при операциях с разными типами данных результат будет более широкого типа

Посмотрим что будет при операциях с типами byte и short

1
2
3
4
byte a = 2; //объявлена первая переменная примитивного типа byte
int b = 3; //объявлена первая переменная примитивного типа int
Type type = new Type(); //создаётся экземпляр класса Type (код выше)
type.check(a + b); //проверяется тип

вывод: This is int type
Чтож, вполне логично исходя из изложенного выше, результат более широкого типа int

Посмотрим на такой пример

1
2
3
4
byte a = 2; //объявлена первая переменная примитивного типа byte
short b = 3; //объявлена первая переменная примитивного типа short
Type type = new Type(); //создаётся экземпляр класса Type (код выше)
type.check(a + b); //проверяется тип

вывод: This is int type

Возможно выглядит неожиданно снова тип int
Если почитать спецификации Java машины можно найти пару строк об этом
Перед любой операции с типами byte или short оба операнда будут сначала конвертированы
в тип int а int + int даёт int

When an operator applies binary numeric promotion to a pair of operands, each of
which must denote a value that is convertible to a numeric type, the following rules apply,
in order, using widening conversion (§5.1.2) to convert operands as necessary:
If any of the operands is of a reference type, unboxing conversion (§5.1.8) is performed. Then:
If either operand is of type double, the other is converted to double.
Otherwise, if either operand is of type float, the other is converted to float.
Otherwise, if either operand is of type long, the other is converted to long.
Otherwise, both operands are converted to type int.

таким образом код

1
2
3
byte a = 2;
byte b = 3;
byte c = a + b;

компилироваться не будет

Подведем итоги

  1. Если другой примитивный целочисленный тип выполняет операцию с типом long результат будет типа Long
  2. Если среди операторов типа long нет, то результатом операций будет тип int

Ну чтож на этом на сегодня всё, можешь самостоятельно попробовать подобные трюки с
типами float и double или char по секрету скажу, там всё примерно также

CATALOG
  1. 1. Как это проверить
  2. 2. Подведем итоги