0. Строковый класс
Строки широко используются в программировании на Java, строки принадлежат объектам в Java, а Java предоставляет класс String для создания строк и управления ими.
本文讲述的String类基于jdk1.8
1. Разница между прямым присвоением и new String()
В обычном коде мы часто видим два способа объявления и присвоения String, но какие тут хитрости? В чем разница между двумя методами? См. пример кода ниже:
public class TestString {
public static void main(String[] args) {
String s1 = new String("hh");
String s2 = new String("hh");
String s3 = "hh";
String s4 = "hh";
System.out.println(s1==s2);
System.out.println(s1==s3);
System.out.println(s3==s4);
}
}
Результат выглядит следующим образом:
false
false
true
Давайте сначала посмотрим на диаграмму модели памяти, задействованную в коде:
1.String s1 = new String("hh");
Во время компиляции "hh" компилируется в файл .class.Constant pool
Medium; во время загрузки класса определить, есть ли в пуле строковых констант "hh", если его в данный момент нет, то изConstant pool
Выньте «hh» и сохраните его в пуле строковых констант. Во время выполнения в стеке создается ссылка на s1, а в куче создается объект, содержимое которого — «hh», а s1 указывает на адрес 1 в куче.
2.String s2 = new String("hh");
Во время компиляции "hh" компилируется в файл .class.Constant pool
В; во время загрузки класса оценивается наличие "hh" в пуле строковых констант. Если он существует в это время, он не будет сохранен в пуле строковых констант. Во время выполнения в стеке создается ссылка на s2, в куче создается объект, содержимое объекта — «hh», а s2 указывает на адрес 2 в куче.
3.String s3 = "hh";
Во время компиляции "hh" компилируется в файл .class.Constant pool
В; во время загрузки класса оценивается наличие "hh" в пуле строковых констант. Если он существует в это время, он не будет сохранен в пуле строковых констант. Во время выполнения в стеке создается ссылка на s3, а s3 указывает на «hh» в пуле строковых констант.
4.String s4 = "hh";
Во время компиляции "hh" компилируется в файл .class.Constant pool
В; во время загрузки класса оценивается наличие "hh" в пуле строковых констант. Если он существует в это время, он не будет сохранен в пуле строковых констант. Во время выполнения в стеке создается ссылка на s4, а s4 указывает на «hh» в пуле строковых констант.
Теперь давайте проанализируем результаты:
1.System.out.println(s1==s2);
Поскольку "==" оценивает, совпадают ли ссылочные адреса, ссылочные адреса s1 и s2 в куче не совпадают, поэтому это ложно.
2.System.out.println(s1==s3);
Ссылочный адрес s1 указывает на адрес 1 в куче, а ссылочный адрес s3 указывает на «hh» в пуле строковых констант, поэтому он ложен.
3.System.out.println(s3==s4);
Ссылочный адрес s3 указывает на «hh» в пуле строковых констант, а ссылочный адрес s4 указывает на «hh» в пуле строковых констант, так что это правда.
**Обзор: **новая String() и прямое присваивание будут оцениваться до того, как строка будет помещена в пул констант.Если она не существует, она будет помещена в него, а если она существует, она не будет помещена в него. . но,new String() откроет дополнительное пространство в кучеСохраняет значение строки. следовательно,Нам следует чаще использовать прямое присваивание в процессе присваивания..
2. Стажер строки()
Метод intern() возвращает нормализованное представление строкового объекта. Этот метод сначала проверит, существует ли строка в пуле строк, и если она существует, он вернет ссылку на строку, в противном случае он добавит строку в пул строк, а затем вернет ссылку на строку.то есть в куче не создаются никакие объекты.
Это следует следующему правилу: для любых двух строк s и t s.intern() == t.intern() истинно тогда и только тогда, когда истинно s.equals(t).
Код теста выглядит следующим образом:
String a = new String("ab");
String b = new String("ab");
String c = "ab";
String d = "a" + "b";
String e = "b";
String f = "a" + e;
System.out.println(b.intern() == a);
System.out.println(b.intern() == c);
System.out.println(b.intern() == d);
System.out.println(b.intern() == f);
System.out.println(b.intern() == a.intern());
Результат выглядит следующим образом:
false
true
true
false
true
Проанализируем результаты построчно:
1.b.intern() == a;
Ссылка b.intern() указывает на ссылку в пуле констант, а ссылка a указывает на ссылку в куче, поэтому false.
2.b.intern() == c;
Ссылка b.intern() указывает на ссылку в пуле констант, а ссылка c указывает на ссылку в пуле констант, так что это правда.
3.b.intern() == d;
Ссылка b.intern() указывает на ссылку в пуле констант, d будет компилировать «a» + «b» в «ab» во время компиляции, так что это то же самое, что d и c, поэтому это правда.
4.b.intern() == f;
Ссылка b.intern() указывает на ссылку в пуле констант, f — это операция с переменными, поэтому ее нельзя сохранить в пуле констант во время компиляции, а ссылка f не указывает на пул констант, поэтому она является ложным.
5.b.intern() == a.intern();
Ссылка b.intern() указывает на ссылку в пуле констант, ссылка a.intern() указывает на ссылку в пуле констант, поэтому верно.
сценарии использования intern()
Поскольку строка содержит конкатенацию переменных строк, строка не попадет в константный пул, поэтому будет большое количество одинаковых строк.Использование intern() может поместить строку в пул констант во время выполнения, вернуть ссылку на строку и избежать повторного создания строки.
Пример ссылки:
static final int MAX = 1000 * 10000;
static final String[] arr = new String[MAX];
public static void main(String[] args) throws Exception {
Integer[] DB_DATA = new Integer[10];
Random random = new Random(10 * 10000);
for (int i = 0; i < DB_DATA.length; i++) {
DB_DATA[i] = random.nextInt();
}
long t = System.currentTimeMillis();
for (int i = 0; i < MAX; i++) {
//将字符串放入常量池并返回引用
arr[i] = new String(String.valueOf(DB_DATA[i % DB_DATA.length])).intern();
}
System.out.println((System.currentTimeMillis() - t) + "ms");
System.gc();
}
Содержание данной статьи приветствуется к обсуждению, если есть какие-то необъективности прошу меня поправить.Примеры в статье специально даны для пояснения.Если есть какие-то неуместности прошу меня простить.