Эта статья была включена из JavaGuide с открытым исходным кодом автора:github.com/Snailclimb([Java Learning + Interview Guide] Копия, которая охватывает основные знания, которые необходимо освоить большинству Java-программистов) Если вы считаете, что это хорошо, вы можете также щелкнуть звезду и поощрить это!
Подробное объяснение области памяти Java
Если не указано иное, все они предназначены для виртуальных машин HotSpot.
Напишите заранее (распространенные вопросы на собеседовании)
фундаментальный вопрос
- Познакомьтесь с областью памяти Java (область данных времени выполнения)
- Процесс создания Java-объектов (пять шагов, рекомендуется прописать их по умолчанию и знать, что делает виртуальная машина на каждом шаге)
- Два способа доступа и поиска объектов (дескриптор и прямой указатель)
Расширьте проблему
- Класс String и постоянный пул
- Классы-оболочки и константные пулы для 8 примитивных типов
I. Обзор
Для программистов Java, в соответствии с механизмом автоматического управления памятью виртуальной машины, больше нет необходимости писать соответствующие операции удаления/освобождения для каждой новой операции, как это делают программисты, разрабатывающие программы C/C++, и не так просто вызвать утечку памяти и память. переполняется проблема. Именно потому, что Java-программисты передают права управления памятью виртуальной машине Java.Если возникают проблемы с утечками и переполнениями памяти, если вы не понимаете, как виртуальная машина использует память, устранить ошибки будет очень сложно. .
Две области данных времени выполнения
В процессе выполнения Java-программ виртуальная машина Java делит управляемую ею память на несколько разных областей данных. JDK.1.8 немного отличается от предыдущих версий, о которых будет рассказано ниже.
До JDK 1.8:
JDK 1.8:
Частная тема:
- счетчик команд
- стек виртуальных машин
- собственный стек методов
Разделено по темам:
- куча
- область метода
- Прямая память (часть нерабочей области данных)
2.1 Счетчик программ
Счетчик программ — это небольшой объем памяти, который можно рассматривать как индикатор номера строки байт-кода, выполняемого текущим потоком.Когда интерпретатор байт-кода работает, он выбирает следующую инструкцию байт-кода для выполнения, изменяя значение этого счетчика.Такие функции, как ветвление, цикл, переход, обработка исключений и восстановление потока, должны полагаться на этот счетчик для завершения.
Кроме того,Чтобы восстановить правильную позицию выполнения после переключения потока, каждый поток должен иметь независимый программный счетчик. Счетчики между потоками не влияют друг на друга и хранятся независимо. Мы называем этот тип области памяти «частной памятью потока».
Из приведенного выше введения мы знаем, что у счетчика программ есть две основные функции:
- Интерпретатор байт-кода последовательно считывает инструкции, изменяя программный счетчик, чтобы реализовать управление потоком кода, например: последовательное выполнение, выбор, цикл, обработка исключений.
- В случае многопоточности счетчик программ используется для записи позиции выполнения текущего потока, чтобы, когда поток переключается обратно, он мог знать, где поток выполнялся в последний раз.
Примечание. Счетчик программ — это единственная область памяти, которая не получает ошибку OutOfMemoryError, ее время жизни создается при создании потока и умирает при завершении потока.
2.2 Стек виртуальной машины Java
Как и программный счетчик, стек виртуальной машины Java также является потоко-приватным, и его жизненный цикл такой же, как и у потока.Он описывает модель памяти выполнения методов Java, и данные каждого вызова метода передаются через куча.
Память Java можно грубо разделить на память кучи (Heap) и память стека (Stack), где стек — это стек виртуальной машины или часть таблицы локальных переменных стека виртуальной машины.(На самом деле стек виртуальной машины Java состоит из кадров стека, и каждый кадр стека содержит: таблицу локальных переменных, стек операндов, динамическую ссылку, информацию о выходе из метода.)
В таблице локальных переменных в основном хранятся различные типы данных, известные компилятору.(логическое, байтовое, символьное, короткое, целое, плавающее, длинное, двойное),ссылка на объект(Тип ссылки, который отличается от самого объекта, может быть указателем на начальный адрес объекта или может указывать на дескриптор, представляющий объект или другое местоположение, связанное с объектом).
В стеке виртуальной машины Java есть два типа ошибок: StackOverFlowError и OutOfMemoryError.
- StackOverFlowError:Если объем памяти стека виртуальной машины Java не позволяет динамическое расширение, когда глубина стека запросов потока превышает максимальную глубину текущего стека виртуальной машины Java, будет выдана ошибка StackOverFlowError.
- OutOfMemoryError:Если размер памяти стека виртуальной машины Java допускает динамическое расширение, а память заканчивается, когда поток запрашивает стек, его больше нельзя динамически расширять, и будет выдан OutOfMemoryError.
Стек виртуальной машины Java также является частным потоком, и каждый поток имеет свой собственный стек виртуальной машины Java, который создается при создании потока и умирает, когда поток умирает.
Расширение: Так как же вызывается метод/функция?
Стек Java можно сравнить со стеком в структуре данных. Основное содержимое, хранящееся в стеке Java, — это кадр стека. Каждый вызов функции будет иметь соответствующий кадр стека, помещаемый в стек Java. После каждого вызова функции кадр стека будет помещен в стек Java.
Есть два способа вернуть метод Java:
- заявление о возврате.
- Сбросить исключение.
Любой способ возврата вызовет выталкивание фрейма стека.
2.3 Стек локальных методов
Это очень похоже на роль, которую играет стек виртуальной машины, разница заключается в следующем:Стек виртуальной машины служит виртуальной машине для выполнения методов Java (то есть байт-кода), в то время как собственный стек методов обслуживает собственные методы, используемые виртуальной машиной.В сочетании со стеком виртуальной машины Java в виртуальной машине HotSpot.
Когда выполняется собственный метод, в стеке собственного метода также создается кадр стека для хранения таблицы локальных переменных, стека операндов, динамической ссылки и информации выхода собственного метода.
После выполнения метода соответствующий кадр стека будет извлечен из стека, и пространство памяти будет освобождено, а также возникнут две ошибки: StackOverFlowError и OutOfMemoryError.
2.4 Кучи
Самая большая часть памяти, управляемая виртуальной машиной Java, куча Java — это область памяти, совместно используемая всеми потоками, создаваемая при запуске виртуальной машины.Единственной целью этой области памяти является хранение экземпляров объектов, и почти все экземпляры объектов и массивы выделяются здесь.
Куча Java — это основная область, управляемая сборщиком мусора, поэтому она также называетсяКуча мусора.С точки зрения сборки мусора, поскольку сборщики в основном используют алгоритм сборки мусора поколений, куча Java также может быть подразделена на: новое поколение и старое поколение: более подробно: пространство Eden, From Survivor, To Survivor и т. д. . . .Целью дальнейшего деления является более эффективное использование памяти или ее более быстрое выделение.
В версиях JDK 7 и до версии JDK 7 память кучи обычно делилась на следующие три части:
- Молодое поколение
- Старое поколение
- Постоянное поколение
После версии JDK 8 область методов (постоянная генерация HotSpot) была полностью удалена (JDK1.7 уже запущена) и заменена метапространством, которое использует прямую память.
Область Эдема и две области Выживших, показанные на рисунке выше, относятся к новому поколению (для различия две области Выживших названы от и до по порядку), а средний слой принадлежит к старому поколению.
В большинстве случаев объект сначала будет размещен в области Эдема.После сборки мусора нового поколения, если объект еще жив, он войдет в s0 или s1, а возраст объекта также увеличится на 1 (возраст предмета после области Эдема -> области Выжившего. Начальный возраст становится равным 1), и когда его возраст увеличится до определенного уровня (по умолчанию 15), он будет переведен в старое поколение. Порог возраста для перевода объекта в старое поколение, который можно передать через параметр-XX:MaxTenuringThreshold
устанавливать.
исправить (issue552): "Когда Hotspot пересекает все объекты, он накапливает занимаемый им размер в соответствии с возрастом от малого до большого. Когда накопленный размер возраста превышает половину области выживания, берется меньшее значение этого возраста и MaxTenuringThreshold, как новое возрастной порог для продвижения по службе».
Код для динамического расчета возраста выглядит следующим образом
uint ageTable::compute_tenuring_threshold(size_t survivor_capacity) { //survivor_capacity是survivor空间的大小 size_t desired_survivor_size = (size_t)((((double) survivor_capacity)*TargetSurvivorRatio)/100); size_t total = 0; uint age = 1; while (age < table_size) { total += sizes[age];//sizes数组是每个年龄段对象大小 if (total > desired_survivor_size) break; age++; } uint result = age < MaxTenuringThreshold ? age : MaxTenuringThreshold; ... }
Скорее всего, в куче появится ошибка OutOfMemoryError, и после возникновения этой ошибки будет несколько проявлений, например:
-
OutOfMemoryError: GC Overhead Limit Exceeded
: Эта ошибка возникает, когда JVM тратит слишком много времени на сборку мусора и может освободить только небольшое пространство кучи. -
java.lang.OutOfMemoryError: Java heap space
: Если при создании нового объекта в памяти кучи недостаточно места для хранения вновь созданного объекта, это приведет кjava.lang.OutOfMemoryError: Java heap space
Ошибка. (Это не имеет ничего общего с физической памятью машины, это связано с размером памяти, которую вы настроили!) - ......
2.5 Область метода
Как и куча Java, область методов — это область памяти, совместно используемая каждым потоком, которая используется для хранения таких данных, как информация о классе, константы, статические переменные и код, скомпилированный компилятором реального времени, которые были загружены виртуальной машиной. . Несмотря на то чтоСпецификация виртуальной машины Java описывает область методов как логическую часть кучи., но у него есть псевдонимБез кучи, цель должна состоять в том, чтобы отличить его от кучи Java.
Область метода также известна как постоянное поколение. Многие люди не могут различить взаимосвязь между областью метода и постоянным поколением, поэтому я также проверил литературу.
2.5.1 Связь между областью метода и постоянной генерацией
«Спецификация виртуальной машины Java» определяет только концепцию области метода и ее функции, но не указывает, как ее реализовать. Тогда реализация области метода должна быть разной на разных JVM.Отношения между областью методов и постоянным поколением очень похожи на отношения между интерфейсом и классом в Java.Класс реализует интерфейс, а постоянное поколение — это способ виртуальной машины HotSpot реализовать область методов в Спецификация виртуальной машины.Другими словами, постоянное поколение — это концепция HotSpot, область методов — это определение в спецификации виртуальной машины Java, спецификация, а постоянное поколение — это реализация, одна — стандарт, а другая — реализация, и другие реализации виртуальных машин не являются постоянными, замените этот оператор.
2.5.2 Общие параметры
До JDK 1.8, когда постоянная генерация не была полностью удалена, для настройки размера области метода обычно использовались следующие параметры.
-XX:PermSize=N //方法区 (永久代) 初始大小
-XX:MaxPermSize=N //方法区 (永久代) 最大大小,超过这个值将会抛出 OutOfMemoryError 异常:java.lang.OutOfMemoryError: PermGen
Условно говоря, поведение сборки мусора в этой области относительно редкое, но оно не является «постоянным» после того, как данные попадают в область метода.
В JDK 1.8 область методов (постоянная генерация HotSpot) была полностью удалена (JDK 1.7 уже запущена) и заменена метапространством, которое использует прямую память.
Вот некоторые общие параметры:
-XX:MetaspaceSize=N //设置 Metaspace 的初始(和最小大小)
-XX:MaxMetaspaceSize=N //设置 Metaspace 的最大大小
Большое отличие от постоянного поколения заключается в том, что если вы не укажете размер, виртуальная машина будет использовать всю доступную системную память по мере создания новых классов.
2.5.3 Зачем заменять PermGen на MetaSpace?
- Все постоянное поколение имеет фиксированный верхний предел размера, установленный самой JVM, который не может быть изменен, а метапространство использует прямую память, которая ограничена доступной памятью машины.Хотя метапространство все еще может переполняться, вероятность возникновения будет меньше исходного.
Когда ваше метапространство переполняется, вы получаете следующую ошибку:
java.lang.OutOfMemoryError: MetaSpace
ты можешь использовать-XX:MaxMetaspaceSize
Флаг устанавливает максимальный размер метапространства, по умолчанию неограничен, что означает, что он ограничен только системной памятью.-XX:MetaspaceSize
Флаг изменения размера определяет начальный размер метапространства. Если этот флаг не указан, размер метапространства будет динамически изменяться в зависимости от потребностей приложения во время выполнения.
-
Метаданные класса хранятся в метапространстве, поэтому количество загруженных классов метаданных не может контролироваться
MaxPermSize
Он контролируется фактическим доступным пространством системы, поэтому можно загрузить больше классов. -
В JDK8 при слиянии кода HotSpot и JRockit у JRockit никогда не было такого понятия, как постоянная генерация, после слияния нет необходимости настраивать такую постоянную генерацию.
2.6 Пул констант времени выполнения
Пул констант времени выполнения является частью области методов. В дополнение к информации описания версии класса, поля, метода, интерфейса и т. д. в файле класса также имеется информация о постоянном пуле (используется для хранения различных литералов и символических ссылок, сгенерированных во время компиляции).
Поскольку пул констант времени выполнения является частью области методов, он, естественно, ограничен памятью области методов.Когда пул констант больше не может применяться к памяти, будет выдана ошибка OutOfMemoryError.
JVM JDK1.7 и более поздних версий переместила пул констант времени выполнения из области методов и открыла область в куче Java (Heap) для хранения пула констант времени выполнения.
2.7 Прямая память
Прямая память не является частью области данных среды выполнения виртуальной машины и не является областью памяти, определенной в спецификации виртуальной машины, но эта часть памяти также часто используется. Это также может вызвать ошибки OutOfMemoryError.
Новое в JDK1.4Класс NIO (новый ввод/вывод), который вводитКаналиБуферВ режиме ввода-вывода он может напрямую использовать библиотеку собственных функций для непосредственного выделения памяти вне кучи, а затем работать с объектом DirectByteBuffer, хранящимся в куче Java, в качестве ссылки на эту память. Это может значительно повысить производительность в некоторых сценариях, посколькуИзбегайте копирования данных между кучей Java и собственной кучей и обратно..
Выделение собственной прямой памяти не будет ограничено кучей Java, но, поскольку это память, оно будет ограничено общим размером собственной памяти и адресным пространством процессора.
Исследование трех объектов виртуальной машины HotSpot
Благодаря приведенному выше введению мы, вероятно, знаем ситуацию с памятью виртуальной машины.Давайте подробно рассмотрим весь процесс выделения объектов, размещения и доступа виртуальной машины HotSpot в куче Java.
3.1 Создание объекта
На следующем рисунке показан процесс создания Java-объектов.Я предлагаю, чтобы лучше было записать его по умолчанию и понять, что делает каждый шаг.
Шаг 1: Проверка загрузки класса
Когда виртуальная машина встречает новую инструкцию, она сначала проверяет, могут ли параметры этой инструкции найти символическую ссылку этого класса в пуле констант, и проверяет, был ли загружен, разрешен и инициализирован класс, представленный этой символической ссылкой. Если нет, то сначала необходимо выполнить соответствующий процесс загрузки класса.
Шаг 2: выделить память
существуетпроверка загрузки классаПосле прохождения следующая виртуальная машина будет новым объектомВыделить память. Размер требуемой объекту памяти можно определить после загрузки класса, а задача выделения места под объект эквивалентна делению блока памяти определенного размера из кучи Java.Распределениеимеют"Столкновение указателей"и«Свободный список»два,Выбор метода распределения определяется тем, является ли куча Java обычной или нет, а является ли куча Java обычной или нет, определяется тем, имеет ли используемый сборщик мусора функцию уплотнения..
Два способа распределения памяти: (дополнительный контент, необходимо освоить)
Какой из двух вышеперечисленных методов выбрать, зависит от того, является ли память кучи Java обычной или нет. Является ли память кучи Java регулярной, зависит от того, является ли алгоритм сборщика мусора "маркировать-очистка" или "маркировать-очищать" (также известный как "маркировать-сжатие"). Стоит отметить, что память алгоритма копирования также регулярно
Проблема параллелизма выделения памяти (дополнительный контент, необходимо освоить)
Очень важным вопросом при создании объектов является безопасность потоков, потому что в реальном процессе разработки объекты создаются очень часто.В качестве виртуальной машины необходимо обеспечить безопасность потоков.Вообще говоря, виртуальная машина использует два метода для обеспечения безопасность потока:
- CAS+ошибка повторной попытки:CAS — это реализация оптимистической блокировки. Так называемая оптимистическая блокировка заключается в том, чтобы завершить операцию без блокировки каждый раз, но предполагая, что конфликта нет.Если из-за конфликта произойдет сбой, она будет повторять попытку, пока не добьется успеха.Виртуальная машина использует CAS в сочетании с неудачной повторной попыткой, чтобы обеспечить атомарность операций обновления.
- TLAB:Заранее выделяйте часть памяти в области Eden для каждого потока.Когда JVM выделяет память для объекта в потоке, она сначала выделяет его в TLAB.Когда объект больше, чем оставшаяся память в TLAB или памяти TLAB исчерпан, вышеупомянутая память снова используется.CAS для выделения памяти
Шаг 3: Инициализируйте нулевое значение
После завершения выделения памяти виртуальная машина должна инициализировать выделенное пространство памяти нулевым значением (исключая заголовок объекта).Этот шаг гарантирует, что поле экземпляра объекта может использоваться непосредственно в коде Java без назначения начального значения. значение, и программа может получить доступ к нулевому значению, соответствующему типу данных этих полей.
Шаг 4: Установите заголовок объекта
После инициализации нулевого значенияВиртуальной машине необходимо произвести необходимые настройки объектаНапример, этот объект является экземпляром этого класса, как найти информацию о метаданных класса, хэш-код объекта, возраст создания GC объекта и т. д.Эта информация хранится в заголовке объекта.Кроме того, в зависимости от текущего состояния виртуальной машины, например, включения блокировки смещения и т. д., заголовок объекта будет установлен по-разному.
Шаг 5: Выполните метод инициализации
После завершения вышеуказанной работы с точки зрения виртуальной машины был создан новый объект, но с точки зрения программы на Java создание объекта только началось.<init>
Метод еще не выполнен, и все поля по-прежнему равны нулю. Таким образом, в общем случае за выполнением новой инструкции последует выполнение<init>
метод, объект инициализируется в соответствии с пожеланиями программиста, так что полностью создается действительно пригодный для использования объект.
3.2 Расположение объектов в памяти
В виртуальной машине Hotspot размещение объектов в памяти можно разделить на 3 области:заголовок объекта,данные экземпляраиВыровнять отступы.
Заголовок объекта виртуальной машины Hotspot состоит из двух частей информации,Первая часть используется для хранения собственных данных времени выполнения самого объекта.(хэш-код, возраст генерации GC, флаги состояния блокировки и т. д.),Другая часть - это указатель типа, то есть указатель объекта на его метаданные класса, и виртуальная машина использует этот указатель, чтобы определить, что объект является экземпляром этого класса.
Часть данных экземпляра — это достоверная информация, которую фактически хранит объект., но и различные типы содержимого полей, определенные в программе.
Заполнение выравнивания не обязательно существует и не имеет особого значения, а служит только заполнителем.Поскольку система автоматического управления памятью виртуальной машины Hotspot требует, чтобы начальный адрес объекта был целым числом, кратным 8 байтам, иными словами, размер объекта должен быть целым числом, кратным 8 байтам. Часть заголовка объекта точно кратна 8 байтам (1 или 2 раза), поэтому, когда часть данных экземпляра объекта не выровнена, ее необходимо заполнить путем заполнения выравнивания.
3.3 Доступ к позиционированию объектов
Создание объекта означает использование объекта, и наша программа на Java работает с конкретным объектом в куче через справочные данные в стеке. Метод доступа к объекту определяется реализацией виртуальной машины. Текущие основные методы доступа:① Используйте ручкуи②Прямой указательДва вида:
- ручка:Если используется дескриптор, то часть памяти будет разделена на кучу Java в качестве пула дескрипторов, адрес дескриптора объекта хранится в ссылке, а дескриптор содержит конкретную информацию об адресе данных и типе экземпляра объекта. данные;
- прямой указатель:Если используется доступ с прямым указателем, то макет объекта кучи Java должен учитывать, как разместить соответствующую информацию данных типа доступа, а адрес, хранящийся в ссылке, является непосредственно объектом.
Оба этих метода доступа к объектам имеют свои преимущества. Самым большим преимуществом использования дескриптора для доступа является то, что в ссылке хранится стабильный адрес дескриптора.При перемещении объекта изменяется только указатель данных экземпляра в дескрипторе, а саму ссылку изменять не нужно. Самое большое преимущество использования метода прямого доступа к указателю заключается в том, что он быстрый, что экономит время на позиционирование указателя.
Четыре ключевые добавки
4.1 Класс String и постоянный пул
Существует два способа создания объектов String:
String str1 = "abcd";//先检查字符串常量池中有没有"abcd",如果字符串常量池中没有,则创建一个,然后 str1 指向字符串常量池中的对象,如果有,则直接将 str1 指向"abcd"";
String str2 = new String("abcd");//堆中创建一个新的对象
String str3 = new String("abcd");//堆中创建一个新的对象
System.out.println(str1==str2);//false
System.out.println(str2==str3);//false
Эти два разных метода создания различны.
- Первый способ — получить объект в пуле констант;
- Второй способ — создать новый объект непосредственно в куче памяти.
Помните это:Всякий раз, когда вы используете новый метод, вам нужно создать новый объект.
Будет легче понять, если я приведу вам другую картинку, источник картинки:woohoo.journal Dev.com/797/what-is…:
Константный пул типа String является особенным. Есть два основных способа его использования:
- Строковые объекты, объявленные непосредственно в двойных кавычках, хранятся непосредственно в пуле констант.
- Если объект String не объявлен с двойными кавычками, можно использовать внутренний метод, предоставляемый String. String.intern() — это собственный метод, его функция такова: если пул констант времени выполнения уже содержит строку, равную содержимому этого объекта String, он возвращает ссылку на строку в пуле констант, если нет — JDK1.7. Метод обработки ранее (за исключением 1.7) заключается в создании строки с тем же содержимым, что и эта строка, в пуле констант и возврате ссылки на строку, созданную в пуле констант.Метод обработки для JDK1.7 и более поздних версий заключается в записи в пуле констант ссылку на эту строку и возвращает эту ссылку.
String s1 = new String("计算机");
String s2 = s1.intern();
String s3 = "计算机";
System.out.println(s2);//计算机
System.out.println(s1 == s2);//false,因为一个是堆内存中的 String 对象一个是常量池中的 String 对象,
System.out.println(s3 == s2);//true,因为两个都是常量池中的 String 对象
Объединение строк:
String str1 = "str";
String str2 = "ing";
String str3 = "str" + "ing";//常量池中的对象
String str4 = str1 + str2; //在堆上创建的新的对象
String str5 = "string";//常量池中的对象
System.out.println(str3 == str4);//false
System.out.println(str3 == str5);//true
System.out.println(str4 == str5);//false
Старайтесь избегать объединения нескольких строк, так как это приведет к воссозданию объекта. Если вам нужно изменить строку, вы можете использовать StringBuilder или StringBuffer.
4.2 String s1 = new String("abc"); Сколько строковых объектов создает это предложение?
Будет создана 1 или 2 строки. Если строковая константа «abc» уже существует в пуле, в пространстве кучи будет создана только одна строковая константа «abc». Если в пуле нет строковой константы «abc», то она будет создана сначала в пуле, а затем в пространстве кучи, поэтому всего будет создано 2 строковых объекта.
проверять:
String s1 = new String("abc");// 堆内存的地址值
String s2 = "abc";
System.out.println(s1 == s2);// 输出 false,因为一个是堆内存,一个是常量池的内存,故两者是不同的。
System.out.println(s1.equals(s2));// 输出 true
результат:
false
true
4.3 Классы-оболочки и пулы констант для 8 основных типов
- Большинство классов-оболочек базовых типов Java реализуют технологию пула констант, а именно Byte, Short, Integer, Long, Character, Boolean; эти пять классов-оболочек по умолчанию создают кэш-данные соответствующего типа значения [-128, 127], но за пределами этой области все равно будут создаваться новые объекты.Зачем устанавливать кеш на интервал [-128, 127]? (См. выпуск/461) компромиссы между производительностью и ресурсами.
- Классы-оболочки Float и Double для двух типов с плавающей запятой не реализуют технологию пула констант.
Integer i1 = 33;
Integer i2 = 33;
System.out.println(i1 == i2);// 输出 true
Integer i11 = 333;
Integer i22 = 333;
System.out.println(i11 == i22);// 输出 false
Double i3 = 1.2;
Double i4 = 1.2;
System.out.println(i3 == i4);// 输出 false
Исходный код целочисленного кеша:
/**
*此方法将始终缓存-128 到 127(包括端点)范围内的值,并可以缓存此范围之外的其他值。
*/
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
Сценарии применения:
- Integer i1=40, Java будет напрямую инкапсулировать код в Integer i1=Integer.valueOf(40) при компиляции, чтобы использовать объекты в пуле констант.
- Integer i1 = new Integer(40), в этом случае создается новый объект.
Integer i1 = 40;
Integer i2 = new Integer(40);
System.out.println(i1==i2);//输出 false
Более богатый пример Integer:
Integer i1 = 40;
Integer i2 = 40;
Integer i3 = 0;
Integer i4 = new Integer(40);
Integer i5 = new Integer(40);
Integer i6 = new Integer(0);
System.out.println("i1=i2 " + (i1 == i2));
System.out.println("i1=i2+i3 " + (i1 == i2 + i3));
System.out.println("i1=i4 " + (i1 == i4));
System.out.println("i4=i5 " + (i4 == i5));
System.out.println("i4=i5+i6 " + (i4 == i5 + i6));
System.out.println("40=i5+i6 " + (40 == i5 + i6));
результат:
i1=i2 true
i1=i2+i3 true
i1=i4 false
i4=i5 false
i4=i5+i6 true
40=i5+i6 true
объяснять:
Оператор i4 == i5 + i6, поскольку оператор + не применяется к объектам Integer, сначала автоматически распаковываются i5 и i6, а значения складываются, то есть i4 == 40. Тогда объект Integer нельзя сравнивать напрямую со значением, поэтому i4 автоматически распаковывается до значения int, равного 40, и, наконец, этот оператор преобразуется в 40 == 40 для числового сравнения.
Ссылаться на
- Глубокое понимание виртуальной машины Java: расширенные функции JVM и рекомендации (второе издание)
- «Практическая виртуальная машина Java»
- docs.Oracle.com/JavaColor/spec…
- woohoo.point software.eat/en/under-diva…
- D zone.com/articles/plus V…
- stackoverflow.com/questions/9…
- Углубленный анализ String#internСпециальности.Meituan.com/2014/03/06/…
публика
Если вы хотите следить за моими обновленными статьями и делиться галантерейными товарами в режиме реального времени, вы можете подписаться на мой официальный аккаунт.
«Нападение на Java-интервью»:"Java Interview Assault" V2.0 PDF-версия, полученная из этого документа для интервью.публикаФоновый ответ"Блиц-интервью по Java"Получите это бесплатно!
Важные учебные ресурсы для Java-инженеров:Некоторые общие учебные ресурсы для инженеров JavaпубликаКлючевое слово ответа за кулисами"1"Вы можете получить его бесплатно без каких-либо уловок.
Рекомендация проекта с открытым исходным кодом
Другие рекомендации автора по проектам с открытым исходным кодом:
- JavaGuide: [Java Learning + Interview Guide] Обложка, содержащая основные знания, которые необходимо освоить большинству Java-программистов.
- springboot-guide: Учебное пособие по Spring Boot, подходящее для начинающих и опытных разработчиков (поддержка в свободное время, добро пожаловать в совместную поддержку).
- programmer-advancement: Я думаю, некоторые хорошие привычки, которые должны быть у техников!
- spring-security-jwt-guide:Начинать с нуля! Spring Security с JWT (включая проверку авторизации) бэкэнд-часть кода.