5.03. Типы данных в Java
Типы данных в Java
★ Тип данных определяет, какие значения может хранить переменная, сколько памяти она занимает, и какие операции можно с ней выполнять. Мы ещё не раз подчеркнём, что Java – статически типизированный язык, и поэтому тип переменной указывается при объявлении и не может меняться.
Типы бывают следующие:
- примитивные типы – базовые типы, встроенные в язык;
- ссылочные типы (объектные) – классы, интерфейсы, массивы, перечисления и т.д.
Примитивные типы данных
★ Примитивные типы данных:
| Тип | Размер | Диапазон | Использование |
|---|---|---|---|
byte | 1 байт | от -128 до 127 | для экономии памяти |
short | 2 байта | от -32 768 до 32 767 | меньше, чем int |
int | 4 байта | ±2 миллиарда | целые числа по умолчанию |
long | 8 байт | ±9 квадриллионов | для больших чисел, литералы с суффиксом L (например, 100L) |
float | 4 байта | приблизительные числа с плавающей точкой | для вещественных чисел, литералы с суффиксом F (например, 100F) |
double | 8 байт | большая точность, чем float | вещественные числа по умолчанию |
boolean | — | true или false | логические значения (булево) |
char | 2 байта | символы в кодировке 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
Таблица расширения типов:
| Исходный тип | Целевой тип |
|---|---|
byte | short, int, long, float, double |
short | int, long, float, double |
char | int, long, float, double |
int | long, float, double |
long | float, double |
float | double |
Сужение (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);
}
Но к циклам мы ещё вернёмся.