Реализация объектов String
String
Объекты — одни из наиболее часто используемых объектов в Java, поэтому Java-компании постоянноString
Реализация объекта оптимизирована с целью улучшенияString
Производительность объекта, посмотрите на следующую картинку, давайте разбираться вместеString
Процесс оптимизации объекта.
1. В Java 6 и более ранних версиях
String
Объект — это объект, который инкапсулирует массив символов. Он в основном имеет четыре переменных-члена: массив символов, смещение смещения, количество символов и хеш-значение.
String
Объект находит массив char[] через свойства offset и count, чтобы получить строку. Это может эффективно и быстро совместно использовать объекты массива, экономя место в памяти, но такой подход может привести к утечкам памяти.
2. С версии Java7 на версию Java8
Начиная с версии Java 7, Java имеетString
В классе произошли некоторые изменения.String
В классе больше нет переменных offset и count. Польза от этогоString
Объект занимает немного меньше памяти, а метод String.substring больше не разделяет char[], что решает проблему утечки памяти, которая может быть вызвана использованием этого метода.
3. Из версии Java9
Изменил массив char[] на массив byte[], зачем вам это нужно? Мы знаем, что char — это два байта, но если хранить однобайтовые символы немного расточительно, то в целях экономии места компания Java изменила его на однобайтовые байты для хранения строк. Это позволяет избежать потерь при хранении одного байта символов.
В Java9 поддерживается новый атрибут coder, который является идентификатором формата кодирования.При вычислении длины строки или вызове функции indexOf() необходимо судить о том, как вычислить длину строки по этому полю . Свойство coder по умолчанию имеет два значения 0 и 1, 0 представляет Latin-1 (однобайтовая кодировка), а 1 представляет кодировку UTF-16. еслиString
Судя по тому, что строка содержит только Latin-1, значение атрибута coder равно 0, иначе 1.
Как создаются объекты String
1. С помощью строковых констант
String str= "pingtouge"
Когда строка создается в таком виде, JVM сначала проверит, существует ли объект в пуле строковых констант. Если он существует, она вернет ссылочный адрес объекта. Если он не существует, он будет создан в пуле строковых констант. пул строковых констант.Строковый объект и возврат ссылки. Преимущество использования этого метода для создания заключается в том, что он позволяет избежать повторного создания строк с одним и тем же значением и экономит память.
2. Способ конструктора String()
String str = new String("pingtouge")
Процесс создания строковых объектов таким способом более сложен и делится на два этапа: во-первых, во время компиляции строкаpingtouge
Он будет добавлен в структуру констант, а строка будет создана в пуле констант при загрузке класса. Затем, когда вызывается new(), JVM вызываетString
конструктор, ссылаясь на постоянный пулpingtouge
нить,
Создать в куче памятиString
объект и возвращает адрес ссылки в куче.
понялString
Существует два способа создания объектов. Давайте проанализируем следующий код, чтобы углубить наше понимание этих двух способов. В следующем фрагменте кодаstr
Равен ли онstr1
Шерстяная ткань?
String str = "pingtouge";
String str1 = new String("pingtouge");
system.out.println(str==str1)
Давайте проанализируем эти строки кода одну за другой, начиная сString str = "pingtouge"
В начале здесь используется метод строковой константы для создания строкового объекта.pingtouge
Когда используется строковый объект, JVM обращается к пулу констант, чтобы выяснить, существует ли строка. Ответ здесь определенно нет, поэтому JVM создаст строковый объект в пуле констант и вернет ссылку на адрес объекта. , такstr
указывает наpingtouge
Адресная ссылка строкового объекта в пуле констант.
ПослеString str1 = new String("pingtouge")
В этой строке кода метод конструктора используется для создания строкового объекта.Согласно нашему пониманию метода конструктора для создания строкового объекта,str1
должен получить кучуpingtouge
Ссылочный адрес строки. так какstr
указывает наpingtouge
Адрес строкового объекта в пуле констант относится кstr1
указывает на кучуpingtouge
адрес строки в кавычках, поэтомуstr
точно не равноstr1
.
Неизменяемость объектов String
из того, что мы знаемString
С момента объекта, я думаю, все знаютString
Объекты неизменны. Так как же это неизменно?Java
Каковы преимущества этого? Давайте кратко обсудим вместе, давайте сначала посмотримString
Кусок исходного кода объекта:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
}
Как видно из этого исходного кода,String
Класс использует модификатор final Мы знаем, что когда класс модифицируется окончательно, это означает, что класс не может быть унаследован, поэтомуString
Классы не могут быть унаследованы. ЭтоString
Неизменная первая точка
Посмотрите дальше вниз, используется для хранения строкchar value[]
массивprivate
иfinal
модификации, мы знаем, что дляfinal
Переменная примитивного типа данных, ее значение не может быть изменено после инициализации. ЭтоString
Неизменный второй пункт.
Зачем компании JavaString
Установите его как неизменяемый, в основном из следующих трех аспектов:
- 1. Обеспечьте безопасность объектов String. Предполагая, что объекты String изменяемы, объекты String могут быть злонамеренно изменены.
- 2. Чтобы значение хеш-атрибута не менялось часто, чтобы обеспечить уникальность, чтобы контейнер, аналогичный HashMap, мог реализовать соответствующую функцию кэширования ключ-значение.
- 3. Можно реализовать пул строковых констант
Оптимизация объектов String
Строка - это то, что мы обычно используемJava
Один из типов, поэтому работа со строками неизбежна.При работе со строками при неправильном использовании производительность будет сильно отличаться. Итак, на что следует обращать внимание в процессе манипуляций со строками?
элегантно соединенные строки
Конкатенация строк — одна из наиболее часто используемых операций со строками, поскольку мы знаем, чтоString
Объекты неизменяемы, поэтому при сплайсинге мы используем как можно меньше+
Выполнить конкатенацию строк или подсознательно думать, что ее нельзя использовать+
Выполните конкатенацию строк, подумайте об использовании+
Выполнение конкатенации строк создает много бесполезных объектов. Это действительно так? Давайте проведем эксперимент. Мы используем+
чтобы объединить следующую строку.
String str8 = "ping" +"tou"+"ge";
Давайте проанализируем, сколько объектов сгенерирует этот код? Если мы проанализируем его так, как мы его понимаем, мы сначала создадимping
объект, затем создайтеpingtou
объект, который будет создан последнимpingtouge
объект, всего создается три объекта. Это действительно так? На самом деле это не так.Компания Java боится, что наши программисты допустят ошибки, поэтому оптимизирует компилятор.Приведенная выше конкатенация строк будет оптимизирована нашим компилятором и оптимизирована вString str8 = "pingtouge";
объект. Помимо оптимизации константной конкатенации строк, для использования+
Нет. Динамически соединяя строки, компилятор также делает соответствующие оптимизации для улучшенияString
производительность, например следующий код:
String str = "pingtouge";
for(int i=0; i<1000; i++) {
str = str + i;
}
Компилятор поможет нам оптимизировать в этом
String str = "pingtouge";
for(int i=0; i<1000; i++) {
str = (new StringBuilder(String.valueOf(str))).append(i).toString();
}
Видно, что Java сделала много оптимизации для этого блока, не позволяя программистуString
Производительность быстро падает. Хотя компания Java сделала соответствующие оптимизации в компиляторе, мы все еще можем увидеть недостатки оптимизации компании Java. При динамическом соращирении строки, хотя StringBuilder используется для сращивания строки, каждый каждый цикл будет генерировать новый StringBuilder Экземпляр, который также уменьшит производительность системы.
Поэтому, когда мы выполняем сращивание строк, нам нужно оптимизировать на уровне кода,При динамическом соединении строк, если безопасность потоков не задействована, мы используем StringBuilder для объединения для повышения производительности системы.Если безопасность потоков задействована, мы используем StringBuffer для объединения строк.
Умное использование метода intern()
* <p>
* When the intern method is invoked, if the pool already contains a
* string equal to this {@code String} object as determined by
* the {@link #equals(Object)} method, then the string from the pool is
* returned. Otherwise, this {@code String} object is added to the
* pool and a reference to this {@code String} object is returned.
* <p>
public native String intern();
Это официальный комментарий к функции intern(), который, вероятно, означает, что функция intern используется для возврата строки в пуле констант.Если строка уже существует в пуле констант, она напрямую вернет ссылку на объект в постоянном пуле. В противном случае добавьте объект в пул констант и верните ссылку.
Существует одинTwitter
инженер вQCon
На Глобальной конференции по разработке программного обеспечения они поделилисьString
Дело об оптимизации объекта, они используют преимуществаString.intern()
Этот метод оптимизирует предыдущее хранилище памяти 20G до нескольких сотен мегабайт памяти. Этого достаточно, чтобы показатьString.intern()
Сила , давайте рассмотрим пример, простойString.intern()
использование.
public static void main(String[] args) {
String str = new String("pingtouge");
String str1 = new String("pingtouge");
System.out.println("未使用intern()方法:"+(str==str1));
System.out.println("未使用intern()方法,str:"+str);
System.out.println("未使用intern()方法,str1:"+str1);
String str2= new String("pingtouge").intern();
String str3 = new String("pingtouge").intern();
System.out.println("使用intern()方法:"+(str2==str3));
System.out.println("使用intern()方法,str2:"+str2);
System.out.println("使用intern()方法,str3:"+str3);
}
String.intern()
метод, создавать строковые объекты с одинаковым значением и возвращать разные ссылочные адреса объектов, использоватьString.intern()
После метода при построении строкового объекта того же значения возвращается тот же адрес ссылки на объект. Это экономит нам много места
String.intern()
Хотя метод хорош, мы должны использовать его в сочетании со сценой и не можем использовать его без разбора, потому что реализация константного пула аналогичнаHashTable
способ реализации,HashTable
Чем больше хранимых данных, тем больше временная сложность обхода. Если данные слишком велики, это увеличит нагрузку на весь пул строковых констант.
Гибкое разделение строк
Разбиение строк — одна из распространенных операций строковых операций.Для разбиения строк большинство людей используют метод Split(), а метод Split() в большинстве случаев использует регулярные выражения.В самом методе нет ничего плохого. , но поскольку производительность регулярных выражений очень нестабильна, неправильное использование вызовет проблемы с возвратом, что может привести к высокой загрузке ЦП. Метод Split() не использует регулярные выражения в следующих двух случаях:
- Если входящий параметр имеет длину 1 и не содержит метасимвол регулярного выражения ".$|()[{^?*+\", регулярное выражение использоваться не будет.
- Если длина переданного параметра равна 2, первый символ — обратная косая черта, а второй символ — не число ASCII или буква ASCII, регулярное выражение не будет использоваться.
Поэтому при разделении строк следует использовать метод Split() с осторожностью. Во-первых, рассмотрите возможность использования метода String.indexOf() для разделения строк. Если String.indexOf() не соответствует требованиям разделения, используйте метод Split() и используйте метод Split.() для разделения строки, вам нужно обратить внимание на проблему поиска с возвратом.
Что касается недостатков статьи, я надеюсь, что вы можете дать больше указаний, учиться вместе и вместе добиваться прогресса.
использованная литература
- Практика настройки производительности Java Лю Чао
Наконец
Сделайте небольшую рекламу, добро пожаловать, чтобы отсканировать код и подпишитесь на общедоступную учетную запись WeChat: «Технический блог брата Пинтоу», давайте вместе добьемся прогресса.