Типы данных Java
Изучите примитивные типы данных Java (byte, short, int, long, float, double, char, boolean) и ссылочные типы.
Java — статически типизированный язык: каждая переменная имеет тип, известный на этапе компиляции. Типы делятся на два семейства: примитивы (встроенные в язык исходные значения) и ссылочные типы (объекты, массивы, всё, что создаётся с помощью new). В этой главе разбираются оба семейства.
Восемь примитивных типов
Примитивы — единственные значения в Java, которые не являются объектами. Они хранят своё значение непосредственно в ячейке памяти переменной. В Java определено ровно восемь примитивных типов:
| Тип | Размер | Диапазон | Значение по умолчанию | Пример литерала |
|---|---|---|---|---|
byte | 8 бит | -128 до 127 | 0 | byte b = 100; |
short | 16 бит | -32 768 до 32 767 | 0 | short s = 30000; |
int | 32 бита | -2³¹ до 2³¹-1 (≈ ±2,1 млрд) | 0 | int i = 1_000_000; |
long | 64 бита | -2⁶³ до 2⁶³-1 | 0L | long l = 9_000L; |
float | 32 бита | IEEE 754, одинарная точность | 0.0f | float f = 3.14f; |
double | 64 бита | IEEE 754, двойная точность | 0.0 | double d = 3.14; |
char | 16 бит | Кодовая единица Unicode (U+0000 до U+FFFF) | \0 | char c = 'A'; |
boolean | Зависит от JVM | true или false | false | boolean b = true; |
Несколько вещей, которые стоит запомнить:
int— стандартный целочисленный тип. Большинство счётчиков и индексов используютint.longследует применять только тогда, когда действительно нужны числа выше ~2 миллиардов.double— стандартный тип с плавающей точкой. Просто написанное3.14— этоdouble;3.14f— этоfloat. Используйтеdouble, если только нехватка памяти не вынуждает перейти наfloat.- Подчёркивания в числовых литералах улучшают читаемость:
1_000_000— то же самое, что1000000. - Значения по умолчанию применяются только к полям, а не к локальным переменным. У локальной переменной нет значения по умолчанию — её необходимо инициализировать перед чтением.
Ссылочные типы
Всё остальное — String, массивы, ваши собственные классы, библиотечные классы — является ссылочным типом. Переменная ссылочного типа не хранит сам объект; она хранит ссылку (по сути, указатель) на объект в куче:
String name = "Ada";
int[] scores = new int[10];
LocalDate today = LocalDate.now();Значение по умолчанию любой ссылочной переменной — null, специальное значение, означающее «нет объекта».
String s = null;
System.out.println(s.length()); // throws NullPointerException at runtimenull — источник одной из самых распространённых ошибок времени выполнения в Java. Глава Исключения Java объясняет, как обрабатывать возникающее при этом исключение NullPointerException.
Классы-обёртки
Каждому примитиву соответствует класс-обёртка — настоящий объект, обёртывающий примитивное значение:
| Примитив | Обёртка |
|---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
Обёртки нужны, когда требуется помещать примитивы в коллекции (которые принимают только объекты):
List<Integer> scores = new ArrayList<>();
scores.add(42); // autoboxed from int → Integer
int first = scores.get(0); // unboxed from Integer → intJava автоматически преобразует примитивы в обёртки и обратно — этот механизм называется автоупаковкой (autoboxing) и распаковкой (unboxing), — поэтому в большинстве случаев вы этого не замечаете.
Замечание о String
String — ссылочный тип, а не примитив. Он достаточно особенный, чтобы язык предоставил для него синтаксис литерала ("text") и оператор +. Строки неизменяемы — после создания их содержимое никогда не меняется. Каждое «изменение» возвращает новую строку. Глава Строки Java рассматривает эту тему подробно.
Выбор типа
Краткое дерево решений для повседневного Java:
- Подсчёт элементов или индексы массивов →
int - Большие числа (размеры файлов, временные метки в миллисекундах) →
long - Деньги →
BigDecimal(неdouble— округление с плавающей точкой вас подведёт) - Один символ →
char - Да/нет →
boolean - Текст →
String - Дата или время → типы из
java.time(LocalDate,Instant,Duration)
Не поддавайтесь желанию «сэкономить память», используя byte или short для обычных целых чисел. JVM оптимизирована под операции с int; short в большинстве случаев реально не экономит память.
Распространённые ловушки
Несколько особенностей поведения типов регулярно удивляют новичков. Знание их заранее экономит часы отладки.
Переполнение целых чисел происходит незаметно
Целочисленная арифметика в Java никогда не выбрасывает исключение при переполнении — она просто циклически обнуляется. Прибавление 1 к наибольшему int даёт наименьший int:
int max = Integer.MAX_VALUE; // 2147483647
System.out.println(max + 1); // -2147483648Если значение может превысить ~2,1 миллиарда, используйте long. Для чисел, способных переполнить даже long, воспользуйтесь BigInteger.
Плавающая точка не является точной
float и double следуют стандарту IEEE 754, который не может точно представить большинство десятичных дробей. Классический пример:
System.out.println(0.1 + 0.2); // 0.30000000000000004Именно поэтому не следует использовать double для денег. Используйте BigDecimal (создавая его из String, например new BigDecimal("0.1")), когда важны точные десятичные значения.
char — это число
char — беззнаковое 16-битное целое число, хранящее кодовую единицу Unicode, поэтому он участвует в арифметических операциях:
char a = 'A';
System.out.println((int) a); // 65
System.out.println((char) (a + 1)); // BСравнивайте обёртки с помощью .equals(), а не ==
== для объектов-обёрток сравнивает ссылки, а не значения. Из-за кэширования при автоупаковке для небольших значений Integer (от -128 до 127) оператор == кажется работающим для малых чисел, но затем даёт сбой для больших:
Integer a = 127, b = 127;
System.out.println(a == b); // true (cached)
Integer c = 128, d = 128;
System.out.println(c == d); // false (different objects)
System.out.println(c.equals(d)); // true (compares values)Всегда используйте .equals() для сравнения значений обёрток. В главе Приведение типов Java описаны правила преобразования между этими типами.
Рабочая демонстрация
Что дальше
В главе Приведение типов Java показано, как выполнять преобразование между числовыми типами и связанными ссылочными типами.