Перейти к основному содержимому

5.03. Типы данных в Java

Разработчику Архитектору

Типы данных в Java

Тип данных определяет, какие значения может хранить переменная, сколько памяти она занимает, и какие операции можно с ней выполнять. Мы ещё не раз подчеркнём, что Java – статически типизированный язык, и поэтому тип переменной указывается при объявлении и не может меняться.

Типы бывают следующие:

  • примитивные типы – базовые типы, встроенные в язык;
  • ссылочные типы (объектные) – классы, интерфейсы, массивы, перечисления и т.д.

Примитивные типы данных

Примитивные типы данных:

ТипРазмерДиапазонИспользование
byte1 байтот -128 до 127для экономии памяти
short2 байтаот -32 768 до 32 767меньше, чем int
int4 байта±2 миллиардацелые числа по умолчанию
long8 байт±9 квадриллионовдля больших чисел, литералы с суффиксом L (например, 100L)
float4 байтаприблизительные числа с плавающей точкойдля вещественных чисел, литералы с суффиксом F (например, 100F)
double8 байтбольшая точность, чем floatвещественные числа по умолчанию
booleantrue или falseлогические значения (булево)
char2 байтасимволы в кодировке Unicodeхранение символов

Число

Число (int, double, и др.).

Примитивные числовые типы: byte, short, int, long, float, double. Не имеют методов, хранятся в стеке.

Простой пример:

int age = 30;

Сложный пример:

double monthlyPayment = loanAmount * 
(monthlyInterestRate * Math.pow(1 + monthlyInterestRate, months)) /
(Math.pow(1 + monthlyInterestRate, months) - 1);

Здесь мы видим расчёт ежемесячного платежа по кредиту по формуле аннуитета. Используются математические функции (Math.pow), арифметические операции и переменные, ранее вычисленные. Результат — значение типа double.

Булево

Булево (boolean).

Примитивный тип, принимающий true или false. Используется в условиях, циклах.

Простой пример:

boolean isActive = true;

Сложный пример:

boolean isEligible = age >= 18 && 
hasValidLicense &&
!violations.isEmpty() &&
violations.stream().noneMatch(v -> v.isSerious());

Проверка eligibility (право на участие) включает несколько условий, включая анализ списка нарушений через Stream API. Используется термин noneMatch для проверки отсутствия серьёзных нарушений.

Ссылочные типы данных

Ссылочные типы данных – это объекты.

Примеры:

String name = "Alice"; // строка
Person person = new Person(); // объект класса
List<String> names = new ArrayList<>(); // коллекция
int[] numbers = {1, 2, 3}; // массив

Ссылочные типы не имеют фиксированного размера, могут быть равны null, передаются по ссылке. Размер динамический, зависит от объекта, однако и производительность чуть ниже.

Строка

Строка (String).

Неизменяемый (immutable) ссылочный тип. Класс java.lang.String.

Простой пример:

String name = "Тимур";

Сложный пример:

String message = String.format(
"Пользователь %s (%s) вошёл %tF в %<tR.%nБаланс: %.2f ₽.",
user.getName(),
user.getRole(),
new Date(),
user.getBalance()
);

Форматированная строка с использованием String.format, включающая дату, время, имя, роль и баланс. Символ %< позволяет повторно использовать предыдущий аргумент (дата), что делает форматирование более эффективным.

Объект

Объект (Object, class).

Все объекты в Java — экземпляры классов. Наследуют от Object.

Простой пример:

Person person = new Person("Иван", 28);

Сложный пример:

List<Person> adults = people.stream()
.filter(p -> p.getAge() >= 18)
.map(p -> new Person(
p.getFirstName().toUpperCase(),
p.getLastName().toUpperCase(),
p.getAge()
))
.collect(Collectors.toList());

Используется Stream API для фильтрации и преобразования списка людей. При этом создаются новые экземпляры Person с изменёнными данными (в верхнем регистре). Демонстрирует функциональный подход в императивном языке.

Массив

Массив (array).

Фиксированной длины упорядоченная коллекция одного типа. Хранится в куче.

Простой пример:

int[] numbers = {1, 2, 3};

Сложный пример:

int[][] matrix = new int[rows][cols];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = i * cols + j + 1;
}
}

Двумерный массив инициализируется по формуле, зависящей от индексов. Результат — матрица с последовательными числами. Показывает работу с многомерными структурами.

Метод

Метод (method).

Функции в Java — методы классов. Не существуют вне контекста класса.

Простой пример:

public String greet(String name) {
return "Привет, " + name + "!";
}

Сложный пример:

public Optional<Double> calculateAverage(List<Integer> values) {
return values == null || values.isEmpty()
? Optional.empty()
: Optional.of(values.stream().mapToDouble(Integer::doubleValue).average().orElse(0.0));
}

Метод возвращает Optional<Double> — безопасный способ представления возможного отсутствия значения. Использует Stream API для вычисления среднего арифметического. Это современный подход, избегающий null.

Прочие типы и операции с ними

Расширение (widening) – неявное (автоматическое) преобразование значения из меньшего типа данных в больший, без потери информации.

byte → short → int → long → float → double

Пример:

int i = 100;
long l = i; // int → long (расширение)

float f = l; // long → float (тоже расширение)
double d = f; // float → double

Таблица расширения типов:

Исходный типЦелевой тип
byteshort, int, long, float, double
shortint, long, float, double
charint, long, float, double
intlong, float, double
longfloat, double
floatdouble

Сужение (narrowing) требует явного приведения типов ((int) myDouble) и может привести к потере данных, в отличие от расширения, которое безопасно (данные не теряются):

double d = 123.456;
int i = (int) d; // 123 — дробная часть отброшена

Массивы в Java – структуры данных, хранящие элементы одного типа под одним именем.

Объявление и инициализация массивов может быть как отдельно:

int[] numbers;           // объявление
numbers = new int[5]; // выделение памяти

…так и в одной строке:

int[] numbers = {1, 2, 3, 4, 5};
//или
int[] numbers = new int[]{1, 2, 3, 4, 5};

Обращение к элементам массива идёт как обычно – они нумеруются с нуля:

int[] nums = {10, 20, 30};
System.out.println(nums[0]); // выводит 10
nums[1] = 25; // изменение значения

Элементы массива можно перебирать при помощи циклов:

for:

for (int i = 0; i < nums.length; i++) {
System.out.println(nums[i]);
}

for-each:

for (int num : nums) {
System.out.println(num);
}

Но к циклам мы ещё вернёмся.