Два семейства: примитивы и ссылки
У каждого значения в Java есть тип, и этот тип относится к одному из двух семейств. Примитивные типы хранят необработанное значение напрямую: число, один символ или истину/ложь. Ссылочные типы хранят ссылку (указатель) на объект, находящийся где-то в памяти: String, массивы и любой класс, который определяете вы или библиотеки.
Это различие важно, потому что примитивы лёгкие и копируются по значению, тогда как ссылочные переменные указывают на общие объекты. Начните с восьми примитивов - это фундамент, на котором строится всё остальное.
Восемь примитивных типов
В Java ровно восемь встроенных примитивных типов. Шесть - числа, один - символ, один - логический:
На что стоит обратить внимание сразу: подчёркивания в 2_000_000 - это всего лишь визуальные разделители, которые компилятор игнорирует; суффиксы L и f обязательны (подробнее ниже); а char использует одинарные кавычки, тогда как String использовал бы двойные.
Выбор числового типа
byte или short вам почти никогда не нужны - они экономят память только в огромных массивах. Настоящий выбор делается между int/long для целых чисел и float/double для дробных.
| Тип | Размер | Использовать, когда |
|---|---|---|
int | 32 бита | Тип по умолчанию для целых чисел (до ~2,1 миллиарда) |
long | 64 бита | Значения свыше ~2 миллиардов: метки времени в миллисекундах, размеры файлов |
double | 64 бита | Тип по умолчанию для дробных - хорошая точность |
float | 32 бита | Только когда памяти мало и точностью можно пожертвовать |
Ловушка - это переполнение. int молча зацикливается, когда выходит за пределы диапазона: никакой ошибки, просто неверный ответ:
maxInt + 1 переполняется до -2147483648, потому что оба операнда - int, и результат остаётся int. Если сначала привести одну сторону к long, вычисление выполнится в 64 битах. Когда значение может быть большим - особенно миллисекунды с 1970 года - берите long.
Литералы и их суффиксы
У «голого» числового литерала есть тип по умолчанию, и это многих подводит. 100 - это int; 3.14 - это double. Чтобы записать литерал long или float, нужно добавить суффикс:
Уберите L из 8_000_000_000L, и код не скомпилируется, потому что литерал превышает диапазон int ещё до того, как попадёт в переменную long. Уберите f из 0.5f, и Java пожалуется, что double нельзя присвоить float без приведения. Суффикс нечувствителен к регистру, но используйте заглавную L - строчная l выглядит ровно как цифра 1.
char - это число под маской
char хранит 16-битную кодовую единицу Unicode, а значит, он одновременно работает как небольшое беззнаковое целое. С ним можно выполнять арифметику и преобразовывать туда-обратно с помощью приведения:
Иногда это удобно для сдвига букв, но не полагайтесь на это для работы с текстом - для этого есть String. Обратите внимание: char использует одинарные кавычки ('A'); двойные кавычки ("A") создают String из одного символа, а это совершенно другой тип.
Значения по умолчанию (и подвох с локальными переменными)
Поля и элементы массивов, которые вы не инициализируете, получают разумное значение по умолчанию. Но это касается только полей и ячеек массивов: локальные переменные не получают никакого значения по умолчанию, и использовать такую до присвоения значения - это ошибка компиляции, а не сюрприз во время выполнения.
Если бы вы вместо этого написали int x; System.out.println(x); внутри main, компилятор отклонил бы это с сообщением «variable x might not have been initialized». Эта строгость - преимущество: она не даёт вам прочитать мусор. Значения по умолчанию, которые стоит запомнить: числовые типы 0, boolean false, char ' ' и любой ссылочный тип null.
Далее: Strings
String - это ссылочный тип, с которым вы будете иметь дело чаще всего: текст, объединённые значения, ввод пользователя. Он ведёт себя иначе, чем рассмотренные здесь примитивы: это объект, он неизменяемый (immutable), а у сравнения строк есть свои подводные камни. Об этом - на следующей странице.
Часто задаваемые вопросы
Сколько типов данных в Java?
В Java восемь примитивных типов: byte, short, int, long, float, double, char и boolean. Всё остальное - String, массивы и любые объекты - это ссылочные типы. Так что количество встроенных примитивов фиксировано и равно восьми, тогда как ссылочных типов неограниченно много, потому что вы (и библиотеки) определяете новые классы.
В чём разница между int и long в Java?
Оба хранят целые числа, но int - 32-битный (диапазон около ±2,1 миллиарда), а long - 64-битный (диапазон около ±9,2 квинтиллиона). Используйте int по умолчанию; переходите на long, когда значение может превысить два миллиарда: метки времени в миллисекундах, размеры файлов, большие счётчики. Литералу long нужен суффикс L, например long big = 10000000000L;.
Каково значение по умолчанию для int в Java?
Поле типа int по умолчанию равно 0 - но значения по умолчанию получают только поля и элементы массивов. long по умолчанию 0L, double - 0.0, boolean - false, char - '\u0000', а любой ссылочный тип - null. Локальные переменные не получают никакого значения по умолчанию - вы обязаны присвоить его перед использованием, иначе код не скомпилируется.