Что такое бокс и распаковка
С точки зрения программиста на C++, многие термины в Java кажутся величественными, но на самом деле они очень просты, особенно упаковка и распаковка. Давайте посмотрим на определения бокса и распаковки:
Упаковка относится к преобразованию примитивного типа в тип-оболочку, а распаковка относится к преобразованию типа-оболочки в примитивный тип данных.
В Java есть восемь основных типов данных: byte/char/boolean/short/int/long/float/double. В мире Java, где все является объектом, конечно, их типы-обертки объектов Byte/Character/Boolean/Short/Integer/Long/Float/Double также незаменимы. Легче всего выразить их взаимосвязь с помощью графика:
public class BoxTest {
public static void main(String[] args) {
Long objectLong100 = 100L;
long baseLong100 = objectLong100;
}
}
вLong objectLong100 = 100L;Вставьте 100L в тип Long и назначьте его переменной типа объекта objectLong100.long baseLong100 = objectLong100;Объект objectLong100 распаковывается и присваивается переменной базового типа baseLong100.
Автоматическая упаковка и распаковка
Что такое автобоксинг и распаковка
Как видно из примера кода 1, преобразование между примитивными типами и типами-оболочками может выполняться автоматически. Декомпиляция приведенного выше кода с помощью javap показывает следующий байт-код:
Как видно из байт-кода, код примера 1 переписывается компилятором в следующий вид:
public class BoxTest {
public static void main(String[] args) {
Long objectLong100 = Long.valueOf(100L);
long baseLong100 = objectLong100.longValue();
}
}
Это один из синтаксических сахаров Java (есть еще много синтаксических сахаров Java, см. "Hollis Original | Если вы не понимаете эти 12 синтаксических сахаров, не говорите, что знаете Java") --- автоматическая упаковка и распаковка, что избавляет программистов от необходимости явного преобразования между примитивными типами и типами-оболочками с помощью кода.
Когда делать автобоксинг и распаковку
Сценарий автобоксинга относительно прост:При присвоении базового типа типу-оболочке назначение здесь не обязательно является символом =/-=/+=, это также может быть вызов методавызовет автобокс. следующее:
public class BoxTest {
public static void main(String[] args) {
//= 赋值自动装箱
Long objectLong = 100L;
//equals 调用自动装箱
if (objectLong.equals(100L)) {
System.out.println("objectLong.equals(100L)");
}
//add 方法调用自动装箱
List<Long> objectLongList = new ArrayList<>();
objectLongList.add(objectLong);
}
}
Точно так же автоматическая распаковка происходит при назначении типа оболочки базовому типу:
public class BoxTest {
public static void unpacking(long var) {
System.out.println("var = " + var);
}
public static void main(String[] args) {
Long objectLong = 100L;
//= 赋值自动拆箱
long basicLong = objectLong;
//方法调用自动拆箱
unpacking(objectLong);
}
}
Но, в отличие от автоупаковки, автораспаковка также происходит, когда:
1. При выполнении математических операций (+, -, *, /, ++, -- и т. д.) между типами-оболочками или между типами-оболочками и примитивными типами.
2. При выполнении операции сравнения ==, != между типом-оболочкой и базовым типом.
1 из них легко понять, ведь все математические операции (например, операции процессора) могут выполняться только между примитивными типами, а не между объектами. 2 Приведите пример, чтобы кратко проиллюстрировать:
public class BoxTest {
public static void main(String[] args) {
Long objectLong = 500L;
long basicLong = 500L;
if (objectLong == basicLong) {
System.out.println("objectLong == basicLong");
} else {
System.out.println("objectLong != basicLong");
}
}
}
выполнить выводobjectLong == basicLong, который представляет собой сравнение между базовым типом и типом оболочки, происходит операция распаковки, поэтому выходные данные равны.Если вы все еще думаете, что basicLong будет упакован в тип-оболочку и сравнен с objectLong, то вы ошибаетесь..
«Готча» в автобоксинге и распаковке
Автоматический бокс и распаковка — это хорошо, но в них тоже много «подводных камней», так что давайте рассмотрим их по порядку. Взгляните на кусок кода:
public class BoxTest {
public static void main(String[] args) {
Long objectLong1 = new Long(10);
Long objectLong2 = new Long(10);
Long objectLong11 = 10L;
Long objectLong22 = 10L;
Long objectLong5 = 1000L;
Long objectLong6 = 1000L;
Long objectLong3 = new Long(10);
long basicLong = 10L;
if(objectLong1 == objectLong2) {
System.out.println("objectLong1 == objectLong2");
} else {
System.out.println("objectLong1 != objectLong2");
}
if(objectLong11 == objectLong22) {
System.out.println("objectLong11 == objectLong22");
} else {
System.out.println("objectLong11 != objectLong22");
}
if(objectLong5 == objectLong6) {
System.out.println("objectLong1 == objectLong2");
} else {
System.out.println("objectLong1 != objectLong2");
}
if (objectLong3 == basicLong) {
System.out.println("objectLong3 == basicLong");
} else {
System.out.println("objectLong3 != basicLong");
}
}
}
Сначала запишите пером то, что, по вашему мнению, получится на выходе, а затем посмотрите на результат на снимке экрана ниже, чтобы убедиться, что ваше «выполнение» правильное.. Результаты приведены ниже:
1. Результат сравнения objectLong1 и objectLong2 не удивителен, потому что это две переменные типа-обертки. Поскольку они не являются одним и тем же объектом, они не равны.
2. Сравнение между objectLong3 и basicLongКогда делать автобоксинг и распаковкуУпомянутый сценарий распаковки также можно быстро понять.
3. Сравнение между objectLong5 и objectLong6 не равно.Большинство людей также могут сделать вывод, что и objectLong5, и objectLong6 автоматически упаковываются в объекты-оболочки, и сравнение == между двумя объектами не равно. Но результат сравнения между objectLong11 и objectLong22 может многих удивить.
Итак, давайте взглянем на метод, который вызывается, когда Long упаковывается автоматически.Long.valueOf(long value)Исходный код:
public final class Long extends Number implements Comparable<Long> {
//......此处省略一堆
private static class LongCache {
private LongCache(){}
static final Long cache[] = new Long[-(-128) + 127 + 1];
static {
for(int I = 0; I < cache.length; I++)
cache[I] = new Long(I - 128);
}
}
//......此处省略一堆
public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // will cache
return LongCache.cache[(int)l + offset];
}
return new Long(l);
}
//......此处省略一堆
}
Можно видеть, что когда значение базового типа для автоупаковки находится между [-128~127], объект, кэшированный в LongCache, возвращается напрямую, а LongCache.cache представляет собой массив, в котором хранится значение -128~ Объект-оболочка для 127, выделяемого при первой загрузке Long.class.Это объясняет, почему 10L автоматически помещается в два одинаковых объекта. И 1000L автобоксируется на два объекта, которые не равны. Первый использует один и тот же объект в кеше в LongCache.cache, а второй создает новый объект каждый раз, когда он автоматически упаковывается..
Другие типы оболочек используют аналогичный подход к кэшированию при упаковке, предотвращая создание слишком большого количества объектов, за исключением Float и Double. Существует три типа методов автобоксинга:
- Исчерпывающий, такой как Byte/Character/Boolean, объект, который кэширует все возможные значения. Таким образом, все их равнозначные объекты-оболочки сравниваются равными.
- Неисчерпаемые прерывистые, такие как Short/Integer/Long, кэшируют только объекты с общими значениями в диапазоне, все ониОбъект-оболочка для некоторых одинаковых значенийСравнение между равным иобъекты-оболочки для большинства одинаковых значенийСравнение не равное.
- Неперечислимые и непрерывные, такие как Float/Double, каждый бокс представляет собой новый объект.
Если вы заинтересованы, вы можете щелкнуть исходный код класса упаковки, чтобы просмотреть его, что относительно просто.
Резюме и рекомендации
1. Тип-обертка по сути является объектом.При автобоксинге сначала создается объект в куче, а затем значению в объекте присваивается значение базового типа.
2. Не используйте ==/!= для сравнения типов оболочек, оболочек и примитивов. Пожалуйста, используйте метод равенства.
3. При выполнении математических операций тип-оболочка будет автоматически распакован, а затем будут выполняться операции с базовым типом..
Добро пожаловать, чтобы подписаться на публичный аккаунт