← Назад к вопросам
Как появляется диапазон значений в примитивных типах данных
1.0 Junior🔥 61 комментариев
#JVM и управление памятью#Основы Java
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как появляется диапазон значений в примитивных типах данных
Диапазоны примитивных типов в Java определяются количеством бит, отводимых на их хранение, и способом представления отрицательных чисел в двоичном коде. Рассмотрю, как это работает на уровне железа.
Основной принцип: Количество бит = Диапазон значений
1 бит → 2^1 = 2 значения (0 или 1)
2 бита → 2^2 = 4 значения
8 бит → 2^8 = 256 значений
16 бит → 2^16 = 65536 значений
32 бита → 2^32 = 4 294 967 296 значений
64 бита → 2^64 = 18 446 744 073 709 551 616 значений
Примитивные типы Java
// Целые типы (signed — со знаком)
type | bits | min | max
---------|------|----------------------|---------------------
byte | 8 | -128 | 127
short | 16 | -32 768 | 32 767
int | 32 | -2 147 483 648 | 2 147 483 647
long | 64 | -9 223 372 036 854 | 9 223 372 036 854
| | 775 808 | 775 807
// Дробные типы
float | 32 | ~1.4 * 10^-45 | ~3.4 * 10^38
double | 64 | ~4.9 * 10^-324 | ~1.7 * 10^308
// Логический тип
boolean | 1 | false | true
// Символ (unsigned — без знака)
char | 16 | 0 ('\\u0000') | 65 535 ('\\uffff')
byte (8 бит)
Двоичное представление:
Полный диапазон 8 бит:
00000000 = 0
00000001 = 1
...
01111111 = 127 ← Максимум для положительного (7 бит данных + 1 знаковый)
10000000 = -128 ← Минимум для отрицательного (дополнительный код)
10000001 = -127
...
11111111 = -1
Почему -128 и 127?
byte b = 127; // Максимум положительного
byte b = -128; // Минимум отрицательного (два дополнения)
// Максимум = 2^(n-1) - 1 = 2^7 - 1 = 127
// Минимум = -2^(n-1) = -2^7 = -128
System.out.println(Byte.MIN_VALUE); // -128
System.out.println(Byte.MAX_VALUE); // 127
int (32 бита)
Структура:
┌─────────────────────────────────────────────┐
│ 1 знаковый бит │ 31 бит данных │
└─────────────────────────────────────────────┘
(MSB - Most Significant Bit)
Положительные (0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx):
от 0 до 2^31 - 1 = 2 147 483 647
Отрицательные (1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx):
от -1 до -2^31 = -2 147 483 648
Всего: 2^32 = 4 294 967 296 значений
Примеры:
int maxInt = 2147483647; // Integer.MAX_VALUE
int minInt = -2147483648; // Integer.MIN_VALUE
System.out.println(Integer.MAX_VALUE); // 2147483647
System.out.println(Integer.MIN_VALUE); // -2147483648
System.out.println(Integer.SIZE); // 32 (бит)
// Переполнение (overflow)
int x = Integer.MAX_VALUE; // 2147483647
int y = x + 1; // -2147483648 (переполнение!)
long (64 бита)
long maxLong = 9223372036854775807L; // 2^63 - 1
long minLong = -9223372036854775808L; // -2^63
System.out.println(Long.MAX_VALUE); // 9223372036854775807
System.out.println(Long.MIN_VALUE); // -9223372036854775808
System.out.println(Long.SIZE); // 64 (бит)
char (16 бит, unsigned)
// char не имеет отрицательных значений
char minChar = 0; // '\u0000'
char maxChar = 65535; // '\uffff'
System.out.println((int) Character.MIN_VALUE); // 0
System.out.println((int) Character.MAX_VALUE); // 65535
System.out.println(Character.SIZE); // 16 (бит)
// Примеры
char a = 'A'; // 65 (ASCII)
char b = '\u0041'; // 65 (Unicode)
char c = 65535; // Максимум
Дополнительный код (Two's Complement)
Почему минимум отличается от максимума на 1?
Java использует дополнительный код для отрицательных чисел:
// Пример: byte (8 бит)
01111111 = 127 (максимум положительный)
01111110 = 126
...
00000001 = 1
00000000 = 0
11111111 = -1 (дополнительный код)
11111110 = -2
...
10000001 = -127
10000000 = -128 (минимум отрицательный)
Откуда берется -1 в дополнительном коде?
00000001 (двоичное 1)
~00000001 = 11111110 (инвертируем)
11111110 + 1 = 11111111 (добавляем 1)
Результат: 11111111 = -1
Почему нет 128 позитива, но есть 128 негатива?
У нас есть 256 уникальных 8-битных комбинаций (2^8)
Мы используем: -128 до 127 = 256 значений
Комбинация 10000000 = -128 (нет +128)
float и double (IEEE 754)
float (32 бита):
┌─┬──────────┬──────────────────────┐
│S│ Exp(8) │ Mantissa(23) │
└─┴──────────┴──────────────────────┘
Sign Exponent Fractional Part
Диапазон: ±1.4 × 10^-45 до ±3.4 × 10^38
Точность: примерно 7 десятичных цифр
System.out.println(Float.MAX_VALUE); // 3.4028235E38
System.out.println(Float.MIN_VALUE); // 1.4E-45
System.out.println(Float.MIN_NORMAL); // 1.17549435E-38
System.out.println(Float.NEGATIVE_INFINITY);
System.out.println(Float.POSITIVE_INFINITY);
System.out.println(Float.NaN);
double (64 бита):
┌─┬───────────────┬──────────────────────────────────┐
│S│ Exp(11) │ Mantissa(52) │
└─┴───────────────┴──────────────────────────────────┘
Диапазон: ±4.9 × 10^-324 до ±1.7 × 10^308
Точность: примерно 15-17 десятичных цифр
System.out.println(Double.MAX_VALUE); // 1.7976931348623157E308
System.out.println(Double.MIN_VALUE); // 4.9E-324
System.out.println(Double.MIN_NORMAL); // 2.2250738585072014E-308
Формулы для диапазонов
// Для типов со знаком (byte, short, int, long)
// Минимум = -2^(n-1)
// Максимум = 2^(n-1) - 1
byte: min = -2^7 = -128, max = 2^7 - 1 = 127
short: min = -2^15 = -32768, max = 2^15 - 1 = 32767
int: min = -2^31 = -2147483648, max = 2^31 - 1 = 2147483647
long: min = -2^63, max = 2^63 - 1
// Для типов без знака (char)
// Минимум = 0
// Максимум = 2^n - 1
char: min = 0, max = 2^16 - 1 = 65535
Практические примеры и ошибки
Переполнение (Overflow):
int max = Integer.MAX_VALUE; // 2147483647
int overflow = max + 1; // -2147483648 (переполнение!)
long safeMax = Integer.MAX_VALUE + 1L; // 2147483648 (правильно)
System.out.println(max); // 2147483647
System.out.println(overflow); // -2147483648
System.out.println(safeMax); // 2147483648
Потеря точности в float:
float f = 16777216f; // 2^24
float f2 = f + 1f; // Потеря точности!
System.out.println(f == f2); // true! Единица потеряна
double d = 9007199254740992d; // 2^53
double d2 = d + 1d; // Потеря точности
System.out.println(d == d2); // true
Безопасное преобразование типов:
long value = 10000000000L; // Больше чем Integer.MAX_VALUE
// ❌ Опасно
int unsafe = (int) value; // Переполнение!
// ✅ Безопасно
if (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE) {
throw new ArithmeticException("Value out of range");
}
int safe = (int) value;
Константы Java для диапазонов
// Использование встроенных констант
Byte.MIN_VALUE // -128
Byte.MAX_VALUE // 127
Short.MIN_VALUE // -32768
Short.MAX_VALUE // 32767
Integer.MIN_VALUE // -2147483648
Integer.MAX_VALUE // 2147483647
Long.MIN_VALUE // -9223372036854775808L
Long.MAX_VALUE // 9223372036854775807L
Character.MIN_VALUE // 0
Character.MAX_VALUE // 65535
Float.MIN_VALUE // 1.4E-45f
Float.MAX_VALUE // 3.4028235E38f
Double.MIN_VALUE // 4.9E-324
Double.MAX_VALUE // 1.7976931348623157E308
// Размеры
Byte.SIZE // 8
Short.SIZE // 16
Integer.SIZE // 32
Long.SIZE // 64
Character.SIZE // 16
Float.SIZE // 32
Double.SIZE // 64
Почему это важно
// Проверка перед операцией
public int safeMultiply(int a, int b) {
if (a > 0 && b > Integer.MAX_VALUE / a) {
throw new ArithmeticException("Overflow");
}
return a * b;
}
// Использование BigDecimal для высокой точности
BigDecimal precise = new BigDecimal("0.1")
.add(new BigDecimal("0.2"));
System.out.println(precise); // 0.3 (точно)
double notPrecise = 0.1 + 0.2;
System.out.println(notPrecise); // 0.30000000000000004 (потеря точности)
Итоги
- Диапазоны определяются количеством бит в представлении типа
- byte: 8 бит → 256 значений (-128 до 127)
- int: 32 бита → 4 млрд значений (-2^31 до 2^31 - 1)
- long: 64 бита → 18 квинтиллионов значений
- char: 16 бит unsigned → 65536 значений (0 до 65535)
- float/double используют IEEE 754 с мантиссой и экспонентой
- Дополнительный код — способ представления отрицательных чисел
- Переполнение (overflow) — когда число выходит за диапазон
- Потеря точности — в float/double при больших числах
- Всегда проверяй диапазоны перед преобразованием типов