Вещи, которые вы не знали о строках Java

Java задняя часть

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 poolMedium; во время загрузки класса определить, есть ли в пуле строковых констант "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();
}

Содержание данной статьи приветствуется к обсуждению, если есть какие-то необъективности прошу меня поправить.Примеры в статье специально даны для пояснения.Если есть какие-то неуместности прошу меня простить.