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

Что такое класс-обертка над примитивом?

1.0 Junior🔥 181 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Классы-обертки над примитивами в Java

Класс-обертка (Wrapper Class) — это объектный класс, который оборачивает примитивный тип данных и предоставляет методы для работы с ним. Это необходимо, потому что в Java примитивные типы — это не объекты, а простые значения.

Зачем нужны обертки?

Три основные причины:

1. Collections требуют объекты

Коллекции (List, Set, Map) работают только с Object, не с примитивами:

// ❌ Это не скомпилируется:
List<int> numbers = new ArrayList<>();

// ✅ Нужна обертка:
List<Integer> numbers = new ArrayList<>();
numbers.add(10);
numbers.add(20);

// Тоже самое для других типов:
List<Double> prices = new ArrayList<>();
List<Boolean> flags = new ArrayList<>();
List<Long> timestamps = new ArrayList<>();

2. Null значения

Примитив не может быть null, но обертка может:

int primitiveInt = null; // ❌ Ошибка компиляции

Integer wrappedInt = null; // ✅ OK

// Практический пример:
public class User {
    private String name;
    private Integer age; // Может быть null, если возраст не указан
    private Integer salary; // Может быть null, если информация конфиденциальна
    
    public User(String name) {
        this.name = name;
        this.age = null; // Нет информации о возрасте
    }
}

3. Методы и константы

Обертки предоставляют полезные методы и константы:

// Integer:
Integer max = Integer.MAX_VALUE; // 2147483647
Integer min = Integer.MIN_VALUE; // -2147483648

// Парсинг:
int num = Integer.parseInt("42");
int hex = Integer.parseInt("FF", 16); // 255

// Конвертация:
String binary = Integer.toBinaryString(42); // "101010"
String hex = Integer.toHexString(255); // "ff"

// Double:
boolean isInfinite = Double.isInfinite(1.0 / 0.0);
boolean isNaN = Double.isNaN(0.0 / 0.0);

// Boolean:
Boolean result = Boolean.parseBoolean("true");

Все типы оберток

primitive    → Wrapper Class
─────────────────────────────
int          → Integer
long         → Long
double       → Double
float        → Float
boolean      → Boolean
char         → Character
short        → Short
byte         → Byte

Автобоксинг и Анбоксинг

В Java 5+ есть автоматическое преобразование между примитивом и оберткой:

// Autoboxing (примитив → обертка):
Integer wrapped = 42; // int автоматически упакуется в Integer

// Unboxing (обертка → примитив):
int primitive = wrapped; // Integer автоматически распакуется в int

// Полная версия без автобоксинга:
Integer wrapped = Integer.valueOf(42);
int primitive = wrapped.intValue();

Практические примеры использования

Пример 1: Работа с коллекциями

public class StatisticsCalculator {
    private final List<Integer> numbers = new ArrayList<>();
    
    public void addScore(int score) {
        numbers.add(score); // Автобоксинг: int → Integer
    }
    
    public double calculateAverage() {
        return numbers.stream()
            .mapToInt(Integer::intValue) // Анбоксинг: Integer → int
            .average()
            .orElse(0.0);
    }
    
    public Optional<Integer> findMax() {
        return numbers.stream()
            .max(Integer::compareTo);
    }
}

Пример 2: API с nullable значениями

public class UserDTO {
    private String name;
    private Integer age; // Может быть null
    private Double salary; // Может быть null
    private Boolean isActive; // Может быть null
    
    public UserDTO(String name, Integer age, Double salary, Boolean isActive) {
        this.name = name;
        this.age = age;
        this.salary = salary;
        this.isActive = isActive;
    }
    
    // Конструктор для минимальной информации:
    public UserDTO(String name) {
        this(name, null, null, true);
    }
}

// Использование:
UserDTO user1 = new UserDTO("Alice", 30, 50000.0, true);
UserDTO user2 = new UserDTO("Bob"); // age и salary = null
UserDTO user3 = new UserDTO("Charlie", 25, null, true); // salary скрыта

Пример 3: Кэширование оберток

// Java кэширует Integer значения от -128 до 127:
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true (один и тот же объект в памяти)

Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false (разные объекты)

// Правильное сравнение оберток:
if (a.equals(b)) { // ✅ Правильно
    System.out.println("Equal");
}

if (a == b) { // ❌ Опасно, может дать неправильный результат
    System.out.println("Same object");
}

Производительность

Обертки медленнее примитивов:

// Бенчмарк:
public void benchmarkPrimitive() {
    long sum = 0;
    for (int i = 0; i < 1_000_000; i++) {
        sum += i; // Работает с примитивом int
    }
    // ~1-2 мс
}

public void benchmarkWrapper() {
    Long sum = 0L;
    for (int i = 0; i < 1_000_000; i++) {
        sum += i; // Идёт анбоксинг и автобоксинг
    }
    // ~10-20 мс (в 10 раз медленнее!)
}

Когда что использовать?

СитуацияИспользуй
Коллекция (List, Set, Map)Обертка (Integer, Double)
Нужен nullОбертка (Integer, Boolean)
Много вычисленийПримитив (int, double)
Свойство в классе может не иметь значенияОбертка
Критична производительность циклаПримитив
Работа с Stream APIОбертка (или специальные IntStream, LongStream)

Частая ошибка: NullPointerException при анбоксинге

// Опасно:
public void process(Integer value) {
    int primitive = value; // Может быть NullPointerException если value = null
    System.out.println(primitive + 10);
}

process(null); // Crash!

// Правильно:
public void process(Integer value) {
    if (value == null) {
        System.out.println("No value provided");
        return;
    }
    int primitive = value;
    System.out.println(primitive + 10);
}

// Или используй Optional:
public void process(Optional<Integer> value) {
    int primitive = value.orElse(0);
    System.out.println(primitive + 10);
}

Вывод

Классы-обертки — это неотъемлемая часть Java, которая позволяет:

  • Использовать примитивы в коллекциях
  • Работать с null значениями
  • Вызывать методы работы с типами

Но помни: обертки медленнее и тяжелее примитивов. Используй их когда нужно, но в критичных по производительности местах предпочитай примитивы и специальные коллекции (IntStream, IntArrayList).