В этой статье автор представит вам очень важную и интересную функцию в Java, которая представляет собой автоматическое бокс и распаковка, и интерпретирует принципы автоматического бокса и распаковки из исходного кода. В то же время эта функция также оставляет ловушку. Если разработчики не обращают внимания, они легко попадут в эту ловушку.
Автобокс
определение
При написании программ Java люди часто определяют целочисленное объект следующим образом:
Целое число I = 100;
Из приведенного выше кода вы можете знать, что я является ссылкой типа Integer, а 100 - основной тип данных в Java (примитивный тип данных). Этот метод непосредственно передачи основного типа данных в соответствующий класс обертки является автоматическим боксом.
В JDK 1.5 автоматическое бокс был представлен впервые. Перед JDK 1.5, если вы хотите определить целочисленный объект со значением 100, вам нужно сделать это:
Целое число I = новое целое число (100);
принцип
Давайте сделаем точку останова в вышеуказанном коде «Целое число I = 100;» и следуйте за ним.
Далее мы видим, что программа переходит к значению (int i) метода целочисленного класса.
/** * Возвращает a <tt> integer </tt> экземпляр, представляющий указанное * <tt> int </tt> значение. * Если новый экземпляр <Tt> Integer </tt> не требуется, этот метод * обычно должен использоваться в предпочтениях конструктору * {@link #integer (int)}, так как этот метод может дать * значительно лучшую производительность пространства и времени путем кэширования * часто запрашиваемых значений. * * @param i an ant <code> int </code> значение. * @return a <tt> integer </tt> экземпляр, представляющий <tt> i </tt>. * @since 1.5 */ public static integer value (int i) {if (i> = -128 && i <= integerCache.high) return integerCache.cache [i + 128]; иначе вернуть новое целое число (i); }Другими словами, упаковка - это JDK, который помогает вам завершить вызов Integer.valueof (100).
Распаковка
определение
Integer integer100 = 100; int int100 = integer100;
Из приведенного выше кода вы можете видеть, что Integer100 является ссылкой на Type Integer, а Int100 - это примитивный тип данных типа Int. Тем не менее, мы можем назначить объект целочисленного типа с переменной соответствующего исходного типа данных. Это распаковка.
Распаковка является противоположностью упаковки. Бокс - это переменная, которая назначает примитивный тип данных для соответствующего инкапсулированного класса. Распаковка означает назначение переменной инкапсулированного класса переменной соответствующего исходного типа данных. Названия упаковки и распаковки также вполне уместны.
принцип
Я считаю, что все догадались, что JDK сделал для нас во время процесса распаковки. Давайте докажем нашу предположение посредством экспериментов.
Установите точку останова на второй строке приведенного выше кода, то есть установите точку останова на «int int100 = integer100;» и следуйте за ним.
Мы видим, что программа переходит на метод Integer's Intvalue ().
/** * Возвращает значение этого <code> integer </code> как * <code> int </code>. */ public int intvalue () {return Value; }То есть JDK помогает нам завершить призыв к методу Intvalue (). Для приведенного выше эксперимента он должен вызвать метод Intvalue () Integer100 и назначить его возвратное значение INT100.
Расширенный
Эксперимент 1
Integer integer400 = 400; int int400 = 400; System.out.println (integer400 == int400);
В третьей строке вышеуказанного кода Integer400 и Int400 выполняют run ==. И эти два - разные типы переменных. Являются ли Integer400 Unbobosing или Int400 упаковка? Каковы результаты операции?
== Операция состоит в том, чтобы определить, равны ли адреса двух объектов или равны значения двух основных типов данных. Следовательно, легко сделать вывод, что если integer400 не является распаком, это означает, что значения двух основных типов сравниваются, а в настоящее время результат выполнения должен быть правдой; Если INT400 упакован, это означает, что адреса двух объектов равны, а в это время должен быть результат, и результат выполнения должен быть ложным. (Что касается того, почему автор назначает их 400, он связан с ловушками, которые будут обсуждаться позже).
Наш фактический результат бега верен. Так что это был integer400. Результаты отслеживания кода доказывают это.
Эксперимент 2
Integer integer100 = 100; int int100 = 100; System.out.println (integer100.equals (int100));
В третьей строке приведенного выше кода параметр метода Integer100 равна int100. Мы знаем, что параметры метода Equals - это объект, а не основной тип данных, поэтому здесь он должен быть упакован Int100. Результаты отслеживания кода доказывают это.
Фактически, если тип параметра в методе является исходным типом данных, а тип параметра, передаваемый в его класс инкапсуляции, он будет автоматически распакован; Соответственно, если тип параметра в методе является типом инкапсуляции, а тип параметра, передаваемый в его исходный тип данных, он будет автоматически.
Эксперимент 3
Integer integer100 = 100; int int100 = 100; long long200 = 200l; System.out.println (integer100 + int100); System.out.println (long200 == (integer100 + int100)); System.out.println (long200.equals (integer100 + int100));
В первом эксперименте мы узнали, что, когда базовый тип данных выполняет операцию == с классом инкапсуляции, класс инкапсуляции будет раскалена. Что если +, -, *, /? Мы можем знать в этом эксперименте.
Если + операция, базовый тип данных будет
• В строке 4 Integer100+Int100 получит объект o типа Integer и значение 200 и выполняет метод ToString () этого объекта и вывода "200";
• В строке 5, Integer100+Int100 получит объект o типа INTEGER и значение 200. Операция == Операция сравнивает этот объект с объектом Long200. Очевидно, false будет выводиться;
• В строке 6 integer100+int100 получит объект o типа INTEGER и значение 200. Метод Equals Long сравнивает Long200 с O, поскольку оба являются инкапсулированными классами различных типов, поэтому выход неверный;
Если + работа, класс инкапсуляции будет распакована, тогда:
• В строке 4, Integer100+Int100 получит базовый тип данных B типа INT и значение 200, затем поле B, чтобы получить O, выполнить метод ToString () этого объекта и вывод «200»;
• В строке 5, Integer100+Int100 получит базовый тип данных B1 типа Int и значение 200. Операция == Операция Unboxes Long200 для получения B2. Очевидно, b1 == b2 и выводит true;
• В строке 6, Integer100+Int100 получит базовый тип данных B типа INT и значение 200. Поле методов Equals Long Equals B, но бокс приводит к объекту o Type Integer, потому что O и Long200 являются объектами разных типов, поэтому выход неверно;
Результатом работы программы является:
200
истинный
ЛОЖЬ
Следовательно, второе предположение правильное, то есть класс инкапсуляции будет распакован во время операции +.
ловушка
Ловушка 1
Integer Integer100 = NULL;
int int100 = integer100;
Эти две строки кодекса являются полностью законными и могут быть скомпилированы полностью, но при запуске будет брошено исключение с нулевым указателем. Среди них Integer100 является объектом целого числа типов, который, конечно, может указывать на NULL. Но во второй строке INTEGER100 будет раскалена, то есть метод IntValue () будет выполнен на нулевом объекте, и, конечно, будет брошено за исключение нулевого указателя. Следовательно, при распаковке вы должны уделять особое внимание, является ли инкапсулированный объект класса нулевым.
Ловушка 2
Целое число i1 = 100;
Целое число i2 = 100;
Целое число i3 = 300;
Целое число i4 = 300;
System.out.println (i1 == i2);
System.out.println (i3 == i4);
Поскольку i1, i2, i3 и i4 - все это целочисленные типы, мы думаем, что результаты работы должны быть ложными. Тем не менее, реальным результатом работы является «System.out.println (i1 == i2);»; что верно, но «System.out.println (i3 == i4);»; который ложный. Это означает, что ссылки двух типов целочисленного целого числа, i1 и i2, указывают на один и тот же объект, в то время как i3 и i4 указывают на разные объекты. Почему? Разве они не все называются методом integer.valueof (int i)?
Давайте снова посмотрим на метод integer.valueof (int i).
/** * Возвращает a <tt> integer </tt> экземпляр, представляющий указанное * <tt> int </tt> значение. * Если новый экземпляр <Tt> Integer </tt> не требуется, этот метод * обычно должен использоваться в предпочтениях конструктору * {@link #integer (int)}, так как этот метод может дать * значительно лучшую производительность пространства и времени путем кэширования * часто запрашиваемых значений. * * @param i an ant <code> int </code> значение. * @return a <tt> integer </tt> экземпляр, представляющий <tt> i </tt>. * @since 1.5 */ public static integer value (int i) {if (i> = -128 && i <= integerCache.high) return integerCache.cache [i + 128]; иначе вернуть новое целое число (i); }Мы можем видеть, что когда i> =-128 и i <= integercache.he, integercache.cache [i + 128] возвращается напрямую. Среди них IntegerCache является внутренним статическим классом целого числа, и его исходный код заключается в следующем:
Частный статический класс IntegerCache {статический конечный int High; Статический конечный целочисленный кеш []; static {final int low = -128; // высокое значение может быть настроено Property int h = 127; if (integercachehighpropvalue! = null) {// Использование Long.decode здесь, чтобы избежать вызывания методов, которые // требуют инициализированного кэта интеллектуального размещения int i = long.decode (integercachehighpropvalue) .intvalue (); i = math.max (i, 127); // максимальный размер массива IS Integer.max_value h = math.min (i, integer.max_value - -low); } high = h; cache = new Integer [(High - low) + 1]; int j = низкий; for (int k = 0; k <cache.length; k ++) cache [k] = новое целое число (j ++); } private integerCache () {}}Мы можем четко видеть, что integerCache имеет статический кэш переменной элемента, который представляет собой массив с 256 элементами. Кэш также инициализируется в IntegerCache, то есть элемент I-Th является целочисленным объектом со значением I-128. -128 до 127 являются наиболее часто используемыми целочисленными объектами, и этот подход также значительно повышает производительность. Также из -за этого «integeri1 = 100; целое число i2 = 100;», i1 и i2 получают тот же объект.
Сравнивая второй эксперимент в расширении, мы узнали, что, когда класс инкапсуляции работает == с основным типом, класс инкапсуляции будет раскалена, а результат распаковки сравнивается с основным типом; В то время как, когда два класса инкапсуляции работают == с другими объектами, они сравнивают адреса двух объектов, то есть, чтобы определить, указывают ли две ссылки на один и тот же объект.
В приведенной выше статье кратко обсуждается автоматическая упаковка и распаковка Java, а ее ловушки - это все контент, которым я делюсь с вами. Я надеюсь, что это может дать вам ссылку, и я надеюсь, что вы сможете поддержать Wulin.com больше.