Wrapper классы ·
‹ Previous Next ›
⏱ 5 min read Modified: 2026-10-16

Классы-обертки в Java (Wrapper Classes). Practical Tasks

Строка int count = stock.get("banana"); не содержит ни одного явного вызова intValue(), но падает с NullPointerException, если ключа "banana" в Map<String, Integer> нет. Такие места проще научиться замечать на практике, чем запомнить по теории.

На этой странице — задачи по классам-оберткам Java (Integer, Long, Double, Boolean) и автоупаковке: методы valueOf(), parseXxx() и xxxValue(), кэш Integer и сравнение через == и equals(), распаковка null, автоупаковка в циклах и выбор перегруженного метода при boxing и varargs. Перед решением прочитайте уроки модуля: Классы обертки в Java, Autoboxing и unboxing и Перегрузка с дополнительными факторами.

Методы Double: valueOf(), parseDouble() и xxxValue()

Напишите программу, которая работает с классом Double и выводит на консоль результат каждого шага.

  1. Создайте объекты Double с помощью обоих вариантов метода valueOf(): из примитива double и из строки.
  2. Преобразуйте строку "300.99" в примитив double методом Double.parseDouble().
  3. Преобразуйте объект Double со значением 300.99 ко всем числовым примитивным типам методами byteValue(), shortValue(), intValue(), longValue(), floatValue() и doubleValue(). Объясните, почему byteValue() возвращает не 300.
  4. Преобразуйте литерал типа double в строку: String d = Double.toString(3.14);
  5. Попробуйте разобрать строки "3,14" и " 3.14 " методом Double.parseDouble(). Ошибку разбора перехватите и выведите сообщение «Не число: ...» вместо аварийного завершения программы.

Нюанс

Double.parseDouble() понимает только точку как разделитель дробной части, независимо от локали, поэтому "3,14" приводит к NumberFormatException. А пробелы по краям строки он, в отличие от Integer.parseInt(), обрезает сам: " 3.14 " разбирается в 3.14.

Solution on Patreon →

Таблица методов классов-оберток

Заполните таблицу: на пересечении строки и столбца поставьте «x», если метод есть у соответствующего класса-обертки. В последнем столбце отметьте, статический это метод или экземплярный.

МетодBooleanByteCharacterDoubleFloatIntegerLongShortСтатический?
byteValue()
doubleValue()
floatValue()
intValue()
longValue()
shortValue()
parseXxx(String)
parseXxx(String, int radix)
valueOf(String, int radix)
toString()
toString(примитив)
toString(примитив, int radix)

Как проверить себя

Сигнатуры всех методов класса выводит команда javap java.lang.Byte (и так для каждой обертки); то же покажет автодополнение в IDE после Byte.. Помните, что Character и Boolean не наследуют класс Number, а значит, и его методов xxxValue().

Solution on Patreon →

Сравнение Integer и Long: == или equals()

Напишите программу, которая сравнивает обертки разными способами. Перед запуском запишите ожидаемый результат каждой строки, затем сверьте его с фактическим выводом.

  1. Объявите Integer a = 127, b = 127; и Integer c = 128, d = 128;. Выведите результаты выражений a == b, c == d, c.equals(d) и c <= d && c >= d.
  2. Объявите Long f = 128L; и выведите f == 128, f.equals(128) и f.equals(128L).
  3. Напишите статический метод boolean sameValue(Integer x, Integer y), который сравнивает значения и не выбрасывает исключений, когда один или оба аргумента равны null (два null считаются равными). Проверьте его на парах (1000, 1000), (null, 5) и (null, null).
  4. Запустите программу с параметром JVM -XX:AutoBoxCacheMax=1000. Какая строка вывода изменилась и почему не изменились остальные?

Подсказка

Две обертки через == сравниваются по ссылкам, а valueOf(), который вызывает автоупаковка, возвращает один и тот же объект только для значений из кэша. Для метода sameValue() пригодится Objects.equals().

Long или long: автоупаковка в цикле

Сравните на практике, во что обходится автоупаковка в «горячем» цикле.

  1. Напишите метод static Long sumBoxed(int n), который суммирует числа от 0 до n - 1 в переменную типа Long, и метод static long sumPrimitive(int n) с накопителем типа long.
  2. Вызовите оба метода для n = 10_000_000 и замерьте время каждого вызова через System.nanoTime(). Выведите сумму и время в миллисекундах. Обе версии должны вывести сумму 49999995000000.
  3. Повторите замер 5 раз в цикле и сравните время первого и последнего повтора.
  4. Посчитайте, сколько новых объектов Long создает вызов sumBoxed(10_000_000), если Long.valueOf() кэширует значения от -128 до 127. Ответ запишите комментарием в коде.

Нюанс

Время зависит от компьютера и версии JVM, поэтому важны не точные миллисекунды, а разница в разы. Первые повторы медленнее из-за прогрева JIT-компилятора; для точных измерений используют библиотеку JMH. Чтобы посчитать объекты, найдите первую итерацию, на которой сумма превысит 127.

Какой перегруженный метод вызовется: расширение, boxing, varargs

Дан класс с четырьмя перегруженными методами print():

public class OverloadQuiz {
    static void print(long x)    { System.out.print("long "); }
    static void print(Integer x) { System.out.print("Integer "); }
    static void print(Object x)  { System.out.print("Object "); }
    static void print(int... x)  { System.out.print("int... "); }

    public static void main(String[] args) {
        byte b = 1;
        char ch = 'a';
        Integer boxed = 3;
        Character c = 'a';

        print(b);
        print(5);
        print(boxed);
        print(ch);
        print(c);
        print(3.0);
        print(1, 2);
        print();
        // print(null);
    }
}
  1. Не запуская программу, запишите, что выведет каждый вызов, и укажите фазу выбора метода (1, 2 или 3). Затем запустите программу и сверьте ответы.
  2. Добавьте метод static void print(double x). Предскажите, какие слова в выводе изменятся, и проверьте.
  3. Раскомментируйте вызов print(null). Скомпилируется ли программа? Объясните сообщение компилятора.

Подсказка

Для каждого вызова проходите фазы по порядку: 1 — точное совпадение и расширение (примитивов и ссылок), 2 — упаковка и распаковка, 3 — раскрытие varargs. Как только на фазе нашелся хотя бы один подходящий метод, следующие фазы не рассматриваются. На фазах 1 и 2 метод print(int... x) виден как метод с параметром int[].

Какие темы закрепляет каждая задача

Первые две задачи проверяют знание методов классов-оберток, следующие три — автоупаковку и распаковку, последняя — выбор перегруженного метода. Если задача не получается, вернитесь к разделу урока из таблицы: в нем есть правило и пример с выводом.

Задача Что проверяет Что повторить
Методы Double valueOf() против parseDouble(), xxxValue(), NumberFormatException Методы классов оберток
Таблица методов какие методы есть у каждой обертки, статические и экземплярные Класс Number
Сравнение Integer и Long кэш -128..127, == против equals(), сравнение с null Сравнение оберток: == или equals()
NullPointerException при распаковке Map.get(), тернарный оператор, Boolean в if NullPointerException при распаковке null
Long или long в цикле цена автоупаковки, LongStream Производительность: автоупаковка в циклах
Какой метод вызовется фазы выбора метода, remove(int) против remove(Object) Три фазы выбора перегруженного метода

Типичные промахи в решениях

Большинство ошибок в этих задачах возникает не из-за незнания синтаксиса, а из-за проверки на «удобных» данных: маленьких числах, заполненных ключах, одном запуске. Перед сдачей решения проверьте его на граничных значениях.

  • Сравнение двух Integer через ==. На значениях до 127 тест проходит, на реальных данных — нет.
  • try-catch вместо исправления. Перехват NullPointerException прячет ошибку; правильнее подставить значение по умолчанию до распаковки (getOrDefault(), Boolean.TRUE.equals()).
  • Один замер времени. Первый запуск цикла включает работу JIT-компилятора, поэтому сравнивайте результаты после нескольких повторов.
  • Выбор метода «по самому похожему типу». Компилятор останавливается на первой фазе, где нашелся подходящий метод, даже если на следующей фазе есть метод с более похожим типом.

Проверь свой код

Перед тем как сверяться с разбором, пройдитесь по рекомендациям по оформлению кода: понятные имена переменных, отсутствие устаревших конструкторов new Integer(...), примитивы там, где значение не может отсутствовать.

Часто задаваемые вопросы

В каком порядке решать задачи по классам-оберткам?

Начните с задач на методы Double и таблицу методов: они проверяют базовый API. Задачи на сравнение Integer, распаковку null и автоупаковку в цикле независимы, их можно решать в любом порядке. Задачу о перегруженных методах оставьте на конец: без понимания автоупаковки ее не решить.

Можно ли в решениях создавать обертки через new Integer() или new Double()?

Лучше не надо: эти конструкторы устарели в Java 9 и с Java 16 помечены forRemoval, компилятор выдает предупреждение. Используйте valueOf(), parseXxx() или автоупаковку. Подробнее — в разделе valueOf() вместо конструкторов.

Как проверить решение, если к задаче нет разбора?

В задачах на автоупаковку и перегрузку есть контрольный вывод или прямое указание запустить код. Сначала запишите предсказание, потом запустите программу и объясните каждое расхождение по правилам из урока. Если не можете объяснить строку вывода — вернитесь к разделу из таблицы выше.

Какие вопросы по классам-оберткам чаще всего задают на собеседовании?

Почему Integer 127 == 127 дает true, а 128 == 128 — false; где возникает NullPointerException при распаковке; почему Long.valueOf(5).equals(5) возвращает false; что удалит list.remove(1) из List<Integer>. Все четыре темы есть в задачах о сравнении Integer, о распаковке null и о перегрузке.

Comments

Please log in or register to have a possibility to add comment.