1. Создание объектов — дело дорогое
Мы знаем, что объекты в java создаются с помощью ключевого слова new. Новый экземпляр, созданный в Java, выделяет память в куче, поэтому создание новых объектов считается дорогостоящей операцией.
Чтобы избежать этого дорогостоящего процесса создания объектов, со временем были разработаны многие фреймворки, которые по-разному объединяют ресурсы.
Например, фреймворки персистентности используют пулы соединений. В Java есть концепция пула строк. Также у нас есть шаблон прототипа для этой цели. Наличие готовых объектов имеет свои преимущества и должно также поощряться.
2. Классы-оболочки реализуют пул объектов
Классы-обертки являются наиболее используемыми классами в приложении Java, подобно классу String. К счастью, подобно классу String, классы-обертки являются неизменяемыми в Java. Поэтому, подобно пулу строк, мы также можем иметь их пул.
Ну, он уже есть. Классы-обертки, предоставляемые JDK, реализуют пул экземпляров. Каждый класс-обертка хранит список часто используемых экземпляров своего типа в виде кэша, и при необходимости мы можем использовать их в нашем коде.
Такое объединение объектов помогает сэкономить много времени во время выполнения программы.
2.1 Демонстрация целочисленного кэша
В классе Integer есть внутренний класс IntegerCache. Это статический внутренний класс, который будет инициализирован только при первом использовании.
Итак, в первый раз, из-за создания кэша, время может быть немного больше, а затем больше времени не потребуется. Но фактическое преимущество — повторное использование памяти.
частный статический класс IntegerCache{частный IntegerCache(){}статический конечный Integer cache[] = new Integer[-(-128) + 127 + 1];статический {для(int i = 0; i < длина.кэша; i++)кэш[i] = новое целое число(i - 128);}}
Когда мы создаем новый экземпляр Integer с заданным синтаксисом, возвращается уже созданный экземпляр Integer, а ссылка сохраняется в i.
Integer i = 10; //ORInteger i = Integer.valueOf(10);
- Обратите внимание, что если мы используем new Integer(10), то будет создан новый экземпляр класса Integer, и кэширование не будет использоваться. Использование ключевого слова new всегда создает новый объект в куче.
- Кэширование доступно только при использовании Integer.valueOf() ИЛИ непосредственного примитивного присваивания(которое в конечном итоге использует функцию valueOf()).
Это реализация метода valueOf(). Посмотрите, как он возвращает уже кэшированный экземпляр.
публичный статический Integer valueOf(int i){окончательное смещение целого числа = 128;если(i >= -128 && i <= 127) // необходимо кэшироватьвернуть IntegerCache.cache[i + offset];}вернуть новое целое число(i);}
2.2.Демо
Давайте посмотрим на пример в работе:
открытый класс IntegerCacheDemo {public static void main(String[] args) {Целое число a1 = 100;Целое число a2 = 100;Целое число a3 = новое целое число(100);System.out.println(a1 == a2); //истинаSystem.out.println(a1 == a3); //ложь}}
- Первый оператор печати выведет значение true; это означает, что обе переменные ссылаются на один и тот же экземпляр.
- Второй оператор print выводит false, поскольку new Integer(..) создал новый свежий экземпляр в памяти.
Поэтому, если мы хотим использовать внутренний кэш, всегда используйте примитивное присваивание для ссылки на переменную или используйте метод valueOf().
3. Изменение размера внутреннего кэша
Если мы хотим сохранить большее количество экземпляров, мы можем использовать параметр времени выполнения, как показано ниже:
-Djava.lang.Integer.IntegerCache.high=<size>
Или мы можем использовать настройку JVM:
-XX:AutoBoxCacheMax=<размер>
Размер 2000 приведет к тому, что кэш будет хранить экземпляры от -127 до 2000. Помните, что на данный момент такого свойства для нижнего предела нет. Возможно, в будущем его также добавят.
4. Другие классы-оболочки
В обсуждении выше я говорил о кэше в классе Integer, но на самом деле все классы-обертки предоставляют пул экземпляров. Давайте быстро их рассмотрим:
- java.lang.Boolean хранит два встроенных экземпляра TRUE и FALSE и возвращает ссылку на них, если ключевое слово new не используется.
- java.lang.Character имеет кэш для символов в диапазоне от 0 до 127 юникодов(ascii-7 / us-ascii).
- java.lang.Long имеет кэш для long от -128 до +127.