Предисловие
Эта статья в основном представляет соответствующий контент о целом в Java и делится им для вашей ссылки и обучения. Я не скажу многое ниже, давайте посмотрим на подробное введение вместе.
Настоящие паразиты
Несколько дней назад я увидел статью, поделившуюся моими моментами «Механизм передачи параметров функций Java - вы действительно это понимаете?》
Некоторые триггеры изучались в целом Java, поэтому я написал эту статью, надеясь, что это будет полезно для вас.
обмен
Давайте сначала посмотрим на пример.
Пожалуйста, используйте Java, чтобы завершить функцию свопа и обменные значения двух целочисленных типов.
public static void test () бросает исключение {целое число a = 1, b = 2; обмен (а, б); System.out.println ("a =" + a + ", b =" + b);} static void swap (целое число A, целое число B) {// Части, которые необходимо реализовать} первый
Если вы не понимаете, как объекты Java выделяются в памяти и как методы передают параметры, вы можете написать следующий код.
Public Static Void Swapone (Integer A, Integer B) бросает исключение {Integer atempvalue = a; a = b; b = atempvalue;} Результаты прогона показывают, что значения A и B не обмениваются.
Итак, давайте посмотрим на то, как объекты Java выделяются в памяти, когда работает вышеуказанная программа:
Назначение адреса объекта
Исходя из этого, мы видим, что локальные переменные таблицы двух методов содержат ссылки на фактические адреса данных объектов A и B.
Функция свопа, реализованная выше, только обменивается ссылками на локальную переменную A и локальную переменную B в функции подкатания и не обменивается фактическими данными в куче JVM.
Следовательно, данные, на которые ссылается A и B в основной функции, не обмениваются, поэтому A и B локальных переменных в основной функции не будут изменяться.
Итак, как вы работаете при обмене данными в основной функции?
Второй раз
Согласно вышеуказанной практике, можем ли мы рассмотреть возможность обмена значениями данных A и B на кучу JVM?
Давайте кратко узнаем о целочисленном объекте. Он имеет только значение INT-типа на уровне объекта для представления значения объекта.
Таким образом, мы используем отражение для изменения значения, код выглядит следующим образом:
public static void swaptwo (Integer A1, Integer B1) выбрасывает исключение {Field valuefield = integer.class.getDeclaredfield ("value"); valuefield.setAccessible (true); int tompavalue = valuefield.getint (a1); valuefield.setint (a1, b1.intvalue ()); valuefield.setint (b1, tompavalue);}Результаты работы соответствуют ожиданиям.
Сюрприз
После того, как вышеупомянутая программа будет запущена, что произойдет, если я объявлю Integer c = 1, d = 2;
Образец программы заключается в следующем:
public static void swaptwo (Integer A1, Integer B1) выбрасывает исключение {Field valuefield = integer.class.getDeclaredfield ("value"); valuefield.setAccessible (true); int tompavalue = valuefield.getint (a1); valuefield.setint (a1, b1.intvalue ()); valuefield.setint (b1, tompavalue);} public static void testthree () бросает исключение {целое число a = 1, b = 2; swaptwo (a, b); System.out.println ("a =" + a + "; b =" + b); Целое число C = 1, d = 2; System.out.println ("c =" + c + "; d =" + d);}Результаты выходных данных следующие:
a = 2; b = 1C = 2; D = 1
Сюрприз или нет! Авария или нет! Стимулирующий или нет!
Глубокий
Что именно случилось? Давайте посмотрим на декомпилированный код:
Автор использовал инструмент IDE для непосредственного декомпиляции этого .CLASS
public static void testthree () бросает исключение {integer a = integer.valueof (1); Integer b = integer.valueof (2); swaptwo (a, b); System.out.println ("a =" + a + "; b =" + b); Integer C = Integer.valueof (1); Integer d = Integer.valueof (2); System.out.println ("c =" + c + "; d =" + d);} В процессе Java автоматически боксирует исходный тип int в целочисленный тип Integer.valueOf(int) .
Должно быть, этот метод инкапсулирует некоторые операции внутренне, что заставляет нас оказывать глобальное влияние после изменения Integer.value .
Все это включает в себя код в этой части кода сразу же приклеен (PS: Автор, который не перетаскивает, является хорошим кодером):
public class integer { / ** * @since 1.5 * / public static integer value (int i) {if (i> = integercache.low && i <= integerCache.high) return integerCache.cache [i + (-integerCache.low)]; вернуть новое целое число (i); } частный статический класс integerCache {static final int low = -128; Статический финал int High; Статический конечный целочисленный кеш []; static {// высокое значение может быть настроено Property int h = 127; String integercachehighpropvalue = sun.misc.vm.getsavedproperty ("java.lang.integer.integercache.high"); if (integercachehighpropvalue! = null) {try {int i = parseint (integerCacheHighPropValue); i = math.max (i, 127); // максимальный размер массива IS integer.max_value h = math.min (i, integer.max_value -(-low) -1); } catch (numberFormateXception nfe) {// Если свойство не может быть проанализировано в int, игнорируйте его. }} high = h; cache = new Integer [(High - low) + 1]; int j = низкий; for (int k = 0; k <cache.length; k ++) cache [k] = новое целое число (j ++); // диапазон [-128, 127] должен быть интернирован (JLS7 5.1.7) Assert integerCache.high> = 127; } private integerCache () {}} Как показано выше, Integer имеет личный статический класс IntegerCache Inside, который статически инициализирует целый массив, содержащий Integer.IntegerCache.low to java.lang.Integer.IntegerCache.high .
Диапазон значений java.lang.Integer.IntegerCache.high находится между [127~Integer.MAX_VALUE - (-low) -1] .
Все объекты, возвращаемые функцией Integer.valueOf(int) в этом интервале, представляют собой смещения, рассчитанные на основе значения int и получены из массива Integer.IntegerCache.cache . Объект такой же, и новый объект не создан.
Таким образом, когда мы изменяем значение Integer.valueOf(1) , все возвращаемые значения Integer.IntegerCache.cache[ 1 - IntegerCache.low ] будут изменены.
Я считаю, что ваш IQ должен быть понят. Если вы не понимаете, пожалуйста, позвоните по номеру 10086 в разделе комментариев.
Хорошо, так что насчет той части, которой нет в [IntegerCache.low~IntegerCache.high) ?
Очевидно, что им повезло, а не кэшируется Integercache, и каждый раз, когда они прибывают, они будут выделять кусок земли (внутренний) (распределение) на JVM.
Задумчивость
Что если я изменю конвертированный параметр на тип на Int?
public static void testone () бросает исключение {int a = 1, b = 2; Swapone (A, B); System.out.println ("a =" + a + ", b =" + b);} static void swapone (int a, int b) {// Части, которые необходимо реализовать} С текущими навыками автора нет решения. Эксперты могут оставить сообщения на официальной учетной записи, большое спасибо!
До сих пор часть обмена была закончена.
1 + 1
Сначала давайте посмотрим на код:
public static void testone () {int one = 1; int два = один + один; System.out.printf ("два =%d", два);} Какой выход?
Если вы скажете 2, чтобы быть уверенным, то вы научились его напрасно, пожалуйста, позвоните по номеру 95169 напрямую.
Я могу точно сказать вам, что это может быть любое значение в интервале [Integer.MIN_VALUE~Integer.MAX_VALUE] .
Сюрприз или нет! Авария или нет! Стимулирующий или нет!
Давайте погладим жареный код один за другим.
Автор использовал инструмент IDE для непосредственного декомпиляции этого .CLASS
public static void testone () {int one = 1; int два = один + один; System.out.printf ("два =%d", два);} Два переменная здесь не вызвала в teger.valueOf(int) , что отличается от того, что я представлял. Я подозреваю, что это горшок IDE.
Так что проверьте скомпилированный байт -код решительно. Ниже приведены некоторые из байткодов выдержки:
LDC "Two =%d" ICONST_1ANEWARRAY JAVA/LANG/ObjectDupiconst_0iload 2invokestatic java/lang/integer.valueof (i) ljava/lang/integer; aastoreinvokevirtual (Ljava/lang/string; [ljava/lang/object;) ljava/io/printstream; pop
Видно, что это действительно горшок IDE. Не только Integer.valueOf(int) называется один раз, но также создается массив объекта.
Полный код Java должен выглядеть так:
public static void testone () {int one = 1; int два = один + один; Object [] params = {integer.valueof (два)}; System.out.printf ("Two =%d", Params);} Поэтому просто измените значение Integer.IntegerCache.cache[2+128] прежде чем будет вызван метод, поэтому добавьте некоторый код в статическую часть инициализации класса.
открытый класс OnePlusone {static {try {class <?> cacheclazz = class.forname ("java.lang.integer $ integerCache"); Field cachefield = cacheclazz.getDeclaredfield ("cache"); cachefield.setAccessible (true); Integer [] cache = (integer []) cachefield.get (null); // изменить здесь на 1 + 1 = 3 кэш [2 + 128] = новое целое число (3); } catch (Exception e) {e.printstackTrace (); }} public static void testone () {int one = 1; int два = один + один; System.out.printf ("два =%d", два); }}два == 2?
После изменения значения Integer.IntegerCache.cache[2 + 128] , является ли переменная двумя равна 2?
public static void testtwo () {int one = 1; int два = один + один; System.out.println (два == 2); System.out.println (integer.valueof (два) == 2);}Вышеуказанный вывод кода выглядит следующим образом
TrueFalse
Поскольку два == 2 не включают преобразование целочисленного бокса или сравнение исходного типа, 2 из исходного типа всегда равен 2.
Реальная форма Integer.valueOf(two)==2 Integer.valueOf(two).intValue == 2
Здесь мы видим, что если вы сравните значение NULL с целочисленной переменной с переменной int с двойным равным знаком, будет брошено NullPointexception.
Каким будет вывод, если метод здесь заменяется System.out.println("Two=" + two) ? Вы можете попробовать это.
PostScript
Xcache
| добрый | Есть кэш | Минимальное значение | Максимальное значение |
|---|---|---|---|
| Логический | никто | - | - |
| Байт | Bytecache | -128 | 127 (исправлен) |
| Короткий | Коротатка | -128 | 127 (исправлен) |
| Персонаж | Характер | 0 | 127 (исправлен) |
| Целое число | IntegerCache | -128 | java.lang.integer.integercache.high |
| Длинный | Longcache | -128 | 127 (исправлен) |
| Плавать | никто | - | - |
| Двойной | Никто | - | - |
java.lang.integer.integercache.high
После прочтения метода получения высокого уровня sun.misc.VM.getSavedProperty классе IntegerCache у вас могут быть следующие вопросы. Мы не будем откладывать и использовать метод «один вопрос-один-ответ».
1. Как передать это значение в JVM?
Как и свойства системы, когда JVM начинается, его передают путем настройки -Djava.lang.Integer.IntegerCache.high=xxx .
2. В чем разница между этим методом и System.getProperty ?
Чтобы отличить параметры, требуемые системой JVM от параметров, используемых пользователем,
Когда java.lang.System.initializeSystemClass , параметры запуска будут сохранены в двух местах:
2.1 Параметры системы, полученные всеми JVM, сохраняются в Sun.misc.vm.savedprops.
Когда JVM начинается, он вызывает метод java.lang.System.initializeSystemClass для инициализации свойства.
В то же время, метод sun.misc.VM.saveAndRemoveProperties также будет вызван для удаления следующих свойств от java.lang.System.props :
Свойства, перечисленные выше, представляют собой все параметры системы, которые необходимо установить для запуска JVM, поэтому для соображений безопасности и соображений изоляции отделяйте их от доступной пользователя System.props.
2.2 Сохраните другие параметры, за исключением следующих параметров, необходимых для запуска JVM в java.lang.system.props.
PS: JDK 1.8.0_91 используется автором
IntegerCache для Java 9
Представьте себе, что если приведенный выше непослушный игровой процесс появится в стороннем пакете зависимостей, определенно будет группа программистов, которые сойдут с ума (пожалуйста, не попробуйте такой плохой игровой процесс, последствия очень серьезны).
К счастью, Java 9 ограничила это. Вы можете написать файл модуля info.java в соответствующем модуле, который ограничивает использование отражения для доступа к членам и т. Д. После объявления при необходимости, код может получить только полки, методы и другую информацию, к которой можно получить доступ с отражением. Только когда класс находится в том же модуле, или модуль открыл пакет для доступа к отражению. Для получения подробной информации, пожалуйста, обратитесь к статье:
Модифицировать IntegerCache в Java 9?
Спасибо Лидии и Асуке за их ценные советы и тяжелую работу по корректуре.
Наконец, я хотел бы поделиться с вами проблемой, которую я не обращаю внимания на целочисленную ценность в Java:
Давайте сначала посмотрим на фрагмент кода:
public static void main (string [] args) {integer a1 = integer.valueof (60); // danielinbiti Integer B1 = 60; System.out.println ("1: ="+(a1 == b1)); Целое число A2 = 60; Целое число B2 = 60; System.out.println ("2: ="+(a2 == b2)); Целое число A3 = новое целое число (60); Целое число B3 = 60; System.out.println ("3: ="+(a3 == b3)); Целое число A3 = новое целое число (60); Целое число B3 = 60; System.out.println ("3: ="+(a3 == b3)); Целое число A4 = 129; Целое число B4 = 129; System.out.println ("4: ="+(a4 == b4)); } Если результат сравнения этого кода не выполнен, я не знаю, каковы ответы в вашем уме.
Чтобы узнать этот ответ, он включает в себя буфер Java и проблемы кучи.
В Java целочисленный тип является буфером для чисел между -128-127, поэтому он согласуется с равным знаком. Но для чисел, не в этом диапазоне, они новички в куче. Следовательно, адресное пространство отличается, поэтому оно не равно.
Integer b3=60 , это процесс упаковки, то есть Integer b3=Integer.valueOf(60)
Следовательно, в будущем, когда вы столкнетесь с целым числом, вам нужно использовать intValue() чтобы сравнить, равны ли значения.
Там нет буфера для двойного.
Ответ
1: = true
2: = true
3: = ложь
4: = ложь
Суммировать
Вышеуказанное - все содержание этой статьи. Я надеюсь, что содержание этой статьи имеет определенную справочную ценность для каждого обучения или работы. Если у вас есть какие -либо вопросы, вы можете оставить сообщение для общения. Спасибо за поддержку Wulin.com.