JavaRush /Java блог /Архив info.javarush /Уровень 29. Ответы на вопросы к собеседованию по теме уро...
DefNeo
36 уровень

Уровень 29. Ответы на вопросы к собеседованию по теме уровня

Статья из группы Архив info.javarush
Уровень 29. Ответы на вопросы к собеседованию по теме уровня - 1
  1. Что такое autoboxing?

    Автоупаковка — это механизм неявной инициализации объектов классов-оберток (Byte, Short, Character, Integer, Long, Float, Double) значениями соответствующих им исходных примитивных типов (соотв. byte, short, char, int, long, float, double), без явного использования конструктора класса.

    Автоупаковка происходит при прямом присвоении примитива — классу-обертке (с помощью оператора "="), либо при передаче примитива в параметры метода (типа "класса-обертки"). Автоупаковке в "классы-обертки" могут быть подвергнуты как переменные примитивных типов, так и константы времени компиляции (литералы и final-примитивы). При этом литералы должны быть синтаксически корректными для инициализации переменной исходного примитивного типа.

    Автоупаковка переменных примитивных типов требует точного соответствия типа исходного примитива — типу "класса-обертки". Например, попытка автоупаковать переменную типа byte в Short, без предварительного явного приведения byte->short вызовет ошибку компиляции.

    Автоупаковка констант примитивных типов допускает более широкие границы соответствия. В этом случае компилятор способен предварительно осуществлять неявное расширение/сужение типа примитивов. Преобразование происходит в два этапа:

    1. неявное расширение(сужение) исходного типа примитива до типа примитива соответствующего классу-обертке (для преобразования int->Byte, сначала компилятор неявно сужает int в byte)

    2. автоупаковку примитива в соотвествующий "класс-обертку" (компилятор автоупаковывает byte->Byte). однако в этом случае существуют два дополнительных ограничения:

      • присвоение примитива — "обертке" может производится только оператором "=" (нельзя передать такой примитив в параметры метода, без явного приведения типов)

      • тип левого операнда не должен быть старше чем Character, тип правого не дожен старше чем int, (допустимо расширение/сужение byte <-> short, byte <-> char, short <-> char
        и только сужение byte <- int, short <- int, char <- int, все остальные варианты требуют явного приведения типов)

    Дополнительная особенность целочисленных "классов-оберток" созданных автоупаковкой констант в диапазоне -128 +127 , в то что они кэшируются JVM. Потому такие обертки с одинаковыми значениями будут являтся ссылками на один объект.

  2. Зачем используется autoboxing?

    Я процитирую лекцию:

    Насколько ты помнишь, в Java есть как типы, унаследованные от класса Object, так и примитивные типы. Но, как оказалось, такая удобная вещь как коллекции и generic’и могут работать только с типами, унаследованными от Object.

  3. Альтернативы autoboxing?

    Не нашел ответа, но запостил на StackOverFlow.

    Исходя из этой дискуссии, получается, что альтернатива autoboxing`у это использование примитивных типов, так как использовние autoboxing`a снижает производительность. Вывод: использовать autoboxing только там где это необходимо.

    Написана статья про Autoboxing: Autoboxing: Traps and Advantages

  4. Типы-обертки для примитивных типов mutable или immutable?

    Immutable, так как примитивные объекты тоже immutable. Чтобы работать как с Mutable типом есть класс MutableInteger, и.т.д.

  5. Как примитивные типы приводятся к непримитивным аналогам?

    На этот и последующий вопросы хорошо отвечает вот эта статья: Автоупаковка и распаковка в Java

    Это заключение из нее: автоупаковка является механизмом для скрытого преобразования примитивных типов данных в соответствующие классы-оболочки (объекты). Компилятор использует метод valueOf() чтобы преобразовать примитивные типы в объекты, а методы IntValue(), doubleValue() и т.д., чтобы получить примитивные типы из объекта (то есть обратное преобразование). Автоупаковка преобразует логический тип boolean в Boolean, byte в Byte, char в Character, float в Float, int в Integer, long в Long, short в Short. Распаковка происходит в обратном направлении.

  6. Как непримитивные типы приводятся к примитивным?

    Выше ответил.

  7. Как сравниваются примитивные и непримитивные типы?

    В лекции это подробно рассматривается, но я нашел так скажем тоже самое, но другими словами.

    В Java есть два способа сравнивать объекты на равенство, == и метод equals().

    == используется для примитивных типов. Для объектов «==» это исключительно сравнение ссылок. Для остальных случаев нужно использовать метод equals(). Кроме того метод hashCode() служит (в теории) для той же цели. Хорошим тоном считается, если вы переопределили equals() и hashCode(). После инициализации неких объектов a и b должно выполняться правило:

    Если выражение a.equals(b) вернет true, то a.hashCode() должен быть равен b.hashCode().

  8. Всегда ли создается новый объект при операции autoboxing?

    Это в лекциях есть:

    Когда мы присваиваем переменной типа Integer значение типа int, при этом вызывается метод Integer.valueOf: функция valueOf не всегда создает новый объект типа Integer. Она кэширует значения от -128 до 127.

    Если передаваемое значение выходит за эти пределы, то новый объект создается, а если нет, то нет.

    Если мы пишем new Integer(), то гарантированно создается новый объект. Если мы вызываем Integer.valueOf(), явно или при autoboxing, то этот метод может вернуть для нас как новый объект, так и отдать объект из кэша, если переданное число лежит в диапазоне от -128 до 127.

  9. Как работает кэширование при операции autoboxing?

    Ответил в вопросе выше, на всякий случай создал вопрос на StackOverFlow, но там отвечают тоже самое

  10. Для каких типов и/или значений работает кэширование?

    В восьмом вопросе. Если у кого – то есть соображения на тему трех последних вопросов, то напишите в комментариях.

Комментарии (17)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
barracuda Уровень 41 Expert
6 ноября 2020
в первом пункте специально не указали Boolean? или есть какой-то подтекст? Boolean b = false;
Soros Уровень 39
15 марта 2020
9. Как работает кэширование при операции autoboxing? Начиная с Java 1.5, для значений в диапазоне от -128 до +127 целочисленные объекты кешируются внутри для повторного использования. В классе-обёртке Integer есть внутренний класс IntegerCache. Он объявлен как private static. В этом внутреннем классе кешированные значения находятся в массиве cache[]. Кеширование выполняется при первом использовании класса-обёртки. После первого использования, вместо создания нового экземпляра (во время autoboxing), используются кешированные объекты. Код метода valueOf() класса Integer выглядит так: Кеширование касается не только класса-оболочки Integer. Имеются аналогичные реализации кеширования для других классов-оболочек целочисленных типов: ByteCache, ShortCache, LongCache, CharacterCache. При создании целочисленного объекта с помощью конструктора кеширование не работает.
Soros Уровень 39
15 марта 2020
5. Как примитивные типы приводятся к непримитивным аналогам? Автоупаковка - ведь не единственный способ приведения примитивного типа к типу-обёртке. autoboxing - это один из вариантов. Альтернатива - явное создание и инициализация объектов-оберток с помощью метода valueOf() или с помощью конструктора.
Soros Уровень 39
15 марта 2020
4. ... так как ПРИМИТИВНЫЕ ОБЪЕКТЫ тоже immutable. Объекты могут быть примитивными?
Artem Boyarshinov Уровень 35
5 декабря 2019
Дополню: 3. Можно создавать объекты классов-оберток с помощью метода valueOf() - это лучший способ с точки зрения производительности, или с помощью конструктора.

Integer value1 = new Integer(5);
Double value2 = Double.valueOf(2.5);
7. Примитивные типы сравниваются с помощью операторов >, <, >=, <=, ==. Классы-обертки сравниваются с помощью методов equals() и compareTo(). Если сравнивается примитивный и непримитивный тип с помощью вышеперечисленных операторов, то перед сравнением будет распаковано значение из непримитивного типа. 10. Кэширование работает для следующих типов объектов: - Byte - для всех значений - Small - от -128 до +127 - Integer - от -128 до +127 - Long - от -128 до +127 - Character - от 0 до 127 - Boolean - все значения
Иван Сапронов Уровень 32
11 июля 2019
Цитата: "Чтобы работать как с Mutable типом есть класс MutableInteger, и.т.д." А что, если не серкет, это за класс такой MutableInteger ? В документации его нет и Гугл про него не знает. Единственное, что я нашёл похожее, это MutableInt, не о нём случайно ли речь?
Дмитрий К. Уровень 33
4 марта 2019
пункт 8 можно добавить информацией из книги Хортсмана "Спецификация автоупаковки требует, чтобы значения типа boolean, byte, char меньше 127, а так же значения типа short и int в пределах от -128 до 127 упаковывались в фиксированные объекты."
Vitaly Khan Уровень 40 Master
17 января 2019
я бы так ответил на следующие вопросы: 2. для улучшения читаемости кода 3. использовать явную инициализацию объектов-оберток в п 7 дополнил бы, что "==" безопасно использовать для сравнения пары "примитив и обертка".
MURS Уровень 35
27 мая 2017
Хочу также добавить интересный вопрос, который вы можете встретить в «интересной» компании. Фишка в том, что расширение до «более широкого» примитивного типа доминирует над автобоксингом этого же типа.
alexn Уровень 35
22 апреля 2017
10 Для каких типов и/или значений работает кэширование? Кэширование работает для следующих значений: true, false, byte, char в диапазоне от \u0000 до \u007f, int или short в диапазоне от -128 до 127. stackoverflow.com/questions/20897020/why-integer-class-caching-values-in-the-range-128-to-127