Java: В чем разница между автобоксом и кастингом?

Этот вопрос звучит так: "Почему автобокс делает некоторые вызовы неоднозначными в Java?"

Но, прочитав ответы, есть несколько ссылок на кастинг, и я не уверен, что полностью понимаю разницу.

Может ли кто-нибудь дать простое объяснение?

7 ответов

Решение

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

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

Кастинг - это общий термин, имеющий два связанных, но разных значения:

  1. Обрабатывать значение одного типа, как если бы оно было значением другого типа. Два примера этого первого использования:

    1.1. Учитывая этот класс B расширяет класс AВы можете попросить myB экземпляр B рассматриваться как пример A написав ((A) myB) где бы ссылка на экземпляр A может появиться. Это на самом деле не производит новый экземпляр A,

    1.2. Коллекции до Java5 хранили весь контент как Object; Обычно для этого требуется использовать приведение после извлечения объекта из коллекции. Например, если вы сохранили String в Map и нужно, чтобы получить его длину, вы бы написать что-то вроде ((String) myMap.get(someKey)).length() где актерский состав потребуется для того, чтобы вызвать length метод String, Опять же, это не вызывает нового String быть созданным.

  2. Явное преобразование одного типа в другой (т.е. явное изменение представления). Пример этого второго использования в выражении ((int) (float_var + 0.5F)) которая округляет переменную с плавающей запятой, добавляя 0,5 (что дает значение с плавающей запятой), а затем явно преобразуя это значение в целое число. Полученное целочисленное значение (после (int) приведение) производится из другого значения путем внутренних вычислений.

Приведение может быть выполнено, когда есть отношение суперкласс / подкласс или интерфейс / разработчик (значение 1 выше) или когда два типа являются примитивными числовыми типами (значение 2). Вы можете посмотреть "расширение" и "сужение" для более подробной информации.

Бокс относится к обертыванию примитивных типов в контейнерных объектах, обычно это делается только тогда, когда у вас должен быть объект (например, сохранение значения в коллекции). Типы примитива и обертки идут парами:

int      Integer
long     Long
boolean  Boolean
...      ...

Распаковка означает просто получение значения примитива из его обертки объекта.

Начиная с Java5, когда вы пишете выражение, которое использует примитивное значение, где требуется соответствующий тип обертки (например, помещение целого числа в коллекцию), компилятор автоматически вставляет код, который фактически оборачивает это примитивное значение. Точно так же он предоставит вам код распаковки.

Поэтому вместо написания (в pre-Java5) что-то вроде:

Map myMap = new HashMap();
...
myMap.put(someKey,Integer.valueOf(3));
...
int nextValue = (myMap.get(someKey)).intValue() + 1;

ты можешь написать:

Map<KeyType,Integer> myMap = new HashMap<KeyType,Integer>();
...
myMap.put(someKey,3);
...
int nextValue = myMap.get(someKey) + 1;

и код упаковки / распаковки вставляется компилятором.

List<String> list = (List<String>)object;

это актерский состав.

void doSomething(Integer i) { ... }
...
doSomeething(5);

это автобокс.

Integer getSomething();
...
int i = getSomething();

это автоматическая распаковка

Автобокс был введен в Java 5 для предотвращения такого кода, как:

map.put("ABC", new Integer(5));
map.put("DEF", new Integer(6));

Теперь вы можете сказать:

map.put("ABC", 5);

Хотя это проще - у него есть несколько ловушек, если вы не совсем уверены в том, что вы делаете.

Можно ли применять Autoboxing и Unboxing в следующем случае?

Long one = 10;
long two = 15;
Long three = 20;

if(one == three) //will this be unboxed or do we need to put a explicit
                 //condition like if(one.intValue() == three.intValue()) 
   System.out.println("Equal");
else 
   System.out.println("Not Equal");  


if(one == two) //will this be unboxed or do we need to put a explicit
               //condition like if(one.intValue() == two) 
   System.out.println("Equal");
else 
   System.out.println("Not Equal");  

Упаковка и распаковка - это тип приведения в Java, где вы приводите примитив к его классу-оболочке или к инверсному, например, логическое значение к логическому (поле) или логическое значение к логическому (unbox).

Типы приведений в Java, например:

  • преобразование идентичности (§5.1.1) Строка в Строку

  • расширяющийся примитивный байт преобразования (§5.1.2) в int

  • сужающее примитивное преобразование (§5.1.3) int в байт

  • расширяющееся ссылочное преобразование (§5.1.5) целое число в число

  • сужение эталонного преобразования (§5.1.6) числа в целое число

  • преобразование бокса (§5.1.7) int в Integer

  • распаковка конверсии (§5.1.8). Целое число в int

Автобокс или автоматическое распаковывание происходит, когда компилятор выполняет преобразование в бокс / распаковку (оно явно не отображается в исходном коде как выражение приведения), например, смотрите вопрос, на который вы ссылались.

Бокс заключает в себе значение внутри контейнера, такое как примитивное значение int внутри объекта Integer

Кастинг это просто как посмотреть на тип.

The former produces another kind of value, the later just modifies how to treat an already existing value

Except casting between primitive types actually modifies their representation. (This doesn't make it clearer does it?)

Другие вопросы по тегам