← Назад к вопросам

Как появляется диапазон значений в примитивных типах данных

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 при больших числах
  • Всегда проверяй диапазоны перед преобразованием типов