Что такое пул Java-строк и чем «s» отличается от новой строки («s»)? [Дубликат]

    

На этот вопрос уже есть ответ здесь:

    

Что означает пул строк ? И в чем разница между следующими объявлениями:

String s = "hello";
String s = new String("hello");

Есть ли разница между хранением этих двух строк в JVM?

104 голоса | спросил sgokhales 21 MaramSun, 21 Mar 2010 09:22:36 +03002010-03-21T09:22:36+03:0009 2010, 09:22:36

6 ответов


0

Пул строк - это конкретная реализация JVM концепции интернирования строк :

  

В информатике, интернирование   метод хранения только одной копии   каждого отдельного строкового значения, которое   должен быть неизменным. Стажировка строк   делает некоторые задачи по обработке строк   более эффективный по времени или пространству на   стоимость требует больше времени, когда   Строка создана или интернирована.   отдельные значения хранятся в строке   внутренний бассейн.

В основном, внутренний пул строк позволяет среде выполнения экономить память путем сохранения неизменяемых строк в пуле, чтобы области приложения могли повторно использовать экземпляры общих строк вместо создания нескольких их экземпляров.

В качестве интересного примечания, интернирование строк - это пример шаблона проектирования с "легким весом" . /р>

  

Flyweight - это программный дизайн   шаблон. Мухи - это объект, который   минимизирует использование памяти, разделяя как   как можно больше данных с другими   похожие объекты; это способ использования   объекты в большом количестве, когда простой   повторное представление будет использовать   недопустимый объем памяти.

ответил Andrew Hare 21 MaramSun, 21 Mar 2010 09:24:37 +03002010-03-21T09:24:37+03:0009 2010, 09:24:37
0

Пул строк позволяет многократно использовать строковые константы, что возможно потому, что строки в Java являются неизменяемыми. Если вы повторяете одну и ту же строковую константу повсюду в вашем Java-коде, у вас может быть только одна копия этой строки в вашей системе, что является одним из преимуществ этого механизма.

Когда вы используете String s = "string constant";, вы получаете копию, которая находится в пуле строк. Однако когда вы делаете String s = new String("string constant");, вы заставляете копию выделяться.

ответил Michael Aaron Safyan 21 MaramSun, 21 Mar 2010 09:28:52 +03002010-03-21T09:28:52+03:0009 2010, 09:28:52
0

JLS

Как упоминал Эндрю , JLS называет эту концепцию "интернированием".

Соответствующий отрывок из JLS 7 3.10.5 :

  

Кроме того, строковый литерал всегда ссылается на один и тот же экземпляр класса String. Это связано с тем, что строковые литералы - или, в более общем случае, строки, являющиеся значениями константных выражений (§15.28), - являются "интернированными", чтобы совместно использовать уникальные экземпляры, используя метод String.intern.

     

Пример 3.10.5-1. Строковые литералы

     

Программа, состоящая из модуля компиляции (§7.3):

package testPackage;
class Test {
    public static void main(String[] args) {
        String hello = "Hello", lo = "lo";
        System.out.print((hello == "Hello") + " ");
        System.out.print((Other.hello == hello) + " ");
        System.out.print((other.Other.hello == hello) + " ");
        System.out.print((hello == ("Hel"+"lo")) + " ");
        System.out.print((hello == ("Hel"+lo)) + " ");
        System.out.println(hello == ("Hel"+lo).intern());
    }
}
class Other { static String hello = "Hello"; }
     

и модуль компиляции:

package other;
public class Other { public static String hello = "Hello"; }
     

производит вывод:

true true true true false true

JVMs

JVMS 7 5.1 сообщает :

  

Строковый литерал является ссылкой на экземпляр класса String и является производным от структуры CONSTANT_String_info (§4.4.3) в двоичном представлении класса или интерфейса. Структура CONSTANT_String_info дает последовательность кодовых точек Unicode, составляющих строковый литерал.

     

Язык программирования Java требует, чтобы идентичные строковые литералы (то есть литералы, которые содержат одинаковую последовательность кодовых точек) должны ссылаться на один и тот же экземпляр класса String (JLS §3.10.5). Кроме того, если метод String.intern вызывается для какой-либо строки, результатом является ссылка на тот же экземпляр класса, который будет возвращен, если эта строка появится в виде литерала. Таким образом, следующее выражение должно иметь значение true:

("a" + "b" + "c").intern() == "abc"
     

Для получения строкового литерала виртуальная машина Java проверяет последовательность кодовых точек, заданных структурой CONSTANT_String_info.

     
  • Если метод String.intern ранее вызывался для экземпляра класса String, содержащего последовательность кодовых точек Unicode, идентичную той, которая задана структурой CONSTANT_String_info, то результатом строкового литерала является ссылка на него. тот же экземпляр класса String.

  •   
  • В противном случае создается новый экземпляр класса String, содержащий последовательность кодовых точек Unicode, заданную структурой CONSTANT_String_info; ссылка на этот экземпляр класса является результатом строкового литерала. Наконец, вызывается метод intern нового экземпляра String.

  •   

Bytecode

Также полезно взглянуть на реализацию байт-кода в OpenJDK 7.

Если мы декомпилируем:

public class StringPool {
    public static void main(String[] args) {
        String a = "abc";
        String b = "abc";
        String c = new String("abc");
        System.out.println(a);
        System.out.println(b);
        System.out.println(a == c);
    }
}

у нас есть постоянный пул:

#2 = String             #32   // abc
[...]
#32 = Utf8               abc

и main:

 0: ldc           #2          // String abc
 2: astore_1
 3: ldc           #2          // String abc
 5: astore_2
 6: new           #3          // class java/lang/String
 9: dup
10: ldc           #2          // String abc
12: invokespecial #4          // Method java/lang/String."<init>":(Ljava/lang/String;)V
15: astore_3
16: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
19: aload_1
20: invokevirtual #6          // Method java/io/PrintStream.println:(Ljava/lang/String;)V
23: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
26: aload_2
27: invokevirtual #6          // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_1
34: aload_3
35: if_acmpne     42
38: iconst_1
39: goto          43
42: iconst_0
43: invokevirtual #7          // Method java/io/PrintStream.println:(Z)V

Обратите внимание, как:

  • 0 и 3: то же самое ldc #2 константа загружена (литералы)
  • 12: создается новый экземпляр строки (с #2 в качестве аргумента)
  • 35: a и c сравниваются как обычные объекты с if_acmpne

Представление константных строк довольно волшебно в байт-коде:

  • у него есть специальный CONSTANT_String_info структура, в отличие от обычных объектов (например, new String)
  • структура указывает на Структура CONSTANT_Utf8_info , котораясодержит данные. Это единственные необходимые данные для представления строки.

и приведенная выше цитата из JVMS, кажется, говорит, что всякий раз, когда Utf8 указывает на одно и то же, идентичные экземпляры загружаются в ldc.

Я провел аналогичные тесты для полей и:

  • static final String s = "abc" указывает на таблицу констант через Атрибут ConstantValue
  • неоконечные поля не имеют этого атрибута, но все же могут быть инициализированы с помощью ldc

Заключение : прямая поддержка байт-кода для пула строк и представление в памяти эффективно.

Бонус: сравните это с целочисленным пулом , который не имеет прямой поддержки байт-кода ( т.е. нет CONSTANT_String_info аналога.

ответил Ciro Santilli 新疆改造中心 六四事件 法轮功 1 Mayam15 2015, 00:58:43
0

Строковые объекты в основном являются обертками вокруг строковых литералов. Уникальные строковые объекты объединяются для предотвращения ненужного создания объекта, и JVM может принять решение о внутреннем объединении строковых литералов. Существует также прямая поддержка байт-кода для констант String, на которые ссылаются несколько раз, при условии, что компилятор поддерживает это.

Когда вы используете литерал, скажем, String str = "abc";, используется объект в пуле. Если вы используете String str = new String("abc");, создается новый объект, но существующий строковый литерал может быть повторно использован либо на уровне JVM, либо на уровне байт-кода (в время компиляции).

Вы можете проверить это сами, создав множество строк в цикле for и используя оператор == для проверки равенства объектов. В следующем примере string.value является приватным для String и содержит строковый литерал. Поскольку это личное, к нему нужно получить доступ через отражение.

public class InternTest {
    public static void main(String[] args) {
        String rehi = "rehi";
        String rehi2 = "rehi";
        String rehi2a = "not rehi";
        String rehi3 = new String("rehi");
        String rehi3a = new String("not rehi");
        String rehi4 = new String(rehi);
        String rehi5 = new String(rehi2);
        String rehi6 = new String(rehi2a);

        String[] arr  = new String[] { rehi, rehi2, rehi2a, rehi3, rehi3a, rehi4, rehi5, rehi6 };
        String[] arr2 = new String[] { "rehi", "rehi (2)", "not rehi", "new String(\"rehi\")", "new String(\"not rehi\")", "new String(rehi)", "new String(rehi (2))", "new String(not rehi)" };

        Field f;
        try {
            f = String.class.getDeclaredField("value");
            f.setAccessible(true);
        } catch (NoSuchFieldException | SecurityException e) {
            throw new IllegalStateException(e);
        }

        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr.length; j++) {
                System.out.println("i: " +arr2[i]+", j: " +arr2[j]);
                System.out.println("i==j: " + (arr[i] == arr[j]));
                System.out.println("i equals j: " + (arr[i].equals(arr[j])));
                try {
                    System.out.println("i.value==j.value: " + (f.get(arr[i]) == f.get(arr[j])));
                } catch (IllegalArgumentException | IllegalAccessException e) {
                    throw new IllegalStateException(e);
                }
                System.out.println("========");
            }
        }
    }
}

Вывод:

i: rehi, j: rehi
i==j: true
i equals j: true
i.value==j.value: true
========
i: rehi, j: rehi (2)
i==j: true
i equals j: true
i.value==j.value: true
========
i: rehi, j: not rehi
i==j: false
i equals j: false
i.value==j.value: false
========
i: rehi, j: new String("rehi")
i==j: false
i equals j: true
i.value==j.value: true
========
i: rehi, j: new String("not rehi")
i==j: false
i equals j: false
i.value==j.value: false
========
i: rehi, j: new String(rehi)
i==j: false
i equals j: true
i.value==j.value: true
========
i: rehi, j: new String(rehi (2))
i==j: false
i equals j: true
i.value==j.value: true
========
i: rehi, j: new String(not rehi)
i==j: false
i equals j: false
i.value==j.value: false
========
i: rehi (2), j: rehi
i==j: true
i equals j: true
i.value==j.value: true
========
i: rehi (2), j: rehi (2)
i==j: true
i equals j: true
i.value==j.value: true
========
i: rehi (2), j: not rehi
i==j: false
i equals j: false
i.value==j.value: false
========
i: rehi (2), j: new String("rehi")
i==j: false
i equals j: true
i.value==j.value: true
========
i: rehi (2), j: new String("not rehi")
i==j: false
i equals j: false
i.value==j.value: false
========
i: rehi (2), j: new String(rehi)
i==j: false
i equals j: true
i.value==j.value: true
========
i: rehi (2), j: new String(rehi (2))
i==j: false
i equals j: true
i.value==j.value: true
========
i: rehi (2), j: new String(not rehi)
i==j: false
i equals j: false
i.value==j.value: false
========
i: not rehi, j: rehi
i==j: false
i equals j: false
i.value==j.value: false
========
i: not rehi, j: rehi (2)
i==j: false
i equals j: false
i.value==j.value: false
========
i: not rehi, j: not rehi
i==j: true
i equals j: true
i.value==j.value: true
========
i: not rehi, j: new String("rehi")
i==j: false
i equals j: false
i.value==j.value: false
========
i: not rehi, j: new String("not rehi")
i==j: false
i equals j: true
i.value==j.value: true
========
i: not rehi, j: new String(rehi)
i==j: false
i equals j: false
i.value==j.value: false
========
i: not rehi, j: new String(rehi (2))
i==j: false
i equals j: false
i.value==j.value: false
========
i: not rehi, j: new String(not rehi)
i==j: false
i equals j: true
i.value==j.value: true
========
i: new String("rehi"), j: rehi
i==j: false
i equals j: true
i.value==j.value: true
========
i: new String("rehi"), j: rehi (2)
i==j: false
i equals j: true
i.value==j.value: true
========
i: new String("rehi"), j: not rehi
i==j: false
i equals j: false
i.value==j.value: false
========
i: new String("rehi"), j: new String("rehi")
i==j: true
i equals j: true
i.value==j.value: true
========
i: new String("rehi"), j: new String("not rehi")
i==j: false
i equals j: false
i.value==j.value: false
========
i: new String("rehi"), j: new String(rehi)
i==j: false
i equals j: true
i.value==j.value: true
========
i: new String("rehi"), j: new String(rehi (2))
i==j: false
i equals j: true
i.value==j.value: true
========
i: new String("rehi"), j: new String(not rehi)
i==j: false
i equals j: false
i.value==j.value: false
========
i: new String("not rehi"), j: rehi
i==j: false
i equals j: false
i.value==j.value: false
========
i: new String("not rehi"), j: rehi (2)
i==j: false
i equals j: false
i.value==j.value: false
========
i: new String("not rehi"), j: not rehi
i==j: false
i equals j: true
i.value==j.value: true
========
i: new String("not rehi"), j: new String("rehi")
i==j: false
i equals j: false
i.value==j.value: false
========
i: new String("not rehi"), j: new String("not rehi")
i==j: true
i equals j: true
i.value==j.value: true
========
i: new String("not rehi"), j: new String(rehi)
i==j: false
i equals j: false
i.value==j.value: false
========
i: new String("not rehi"), j: new String(rehi (2))
i==j: false
i equals j: false
i.value==j.value: false
========
i: new String("not rehi"), j: new String(not rehi)
i==j: false
i equals j: true
i.value==j.value: true
========
i: new String(rehi), j: rehi
i==j: false
i equals j: true
i.value==j.value: true
========
i: new String(rehi), j: rehi (2)
i==j: false
i equals j: true
i.value==j.value: true
========
i: new String(rehi), j: not rehi
i==j: false
i equals j: false
i.value==j.value: false
========
i: new String(rehi), j: new String("rehi")
i==j: false
i equals j: true
i.value==j.value: true
========
i: new String(rehi), j: new String("not rehi")
i==j: false
i equals j: false
i.value==j.value: false
========
i: new String(rehi), j: new String(rehi)
i==j: true
i equals j: true
i.value==j.value: true
========
i: new String(rehi), j: new String(rehi (2))
i==j: false
i equals j: true
i.value==j.value: true
========
i: new String(rehi), j: new String(not rehi)
i==j: false
i equals j: false
i.value==j.value: false
========
i: new String(rehi (2)), j: rehi
i==j: false
i equals j: true
i.value==j.value: true
========
i: new String(rehi (2)), j: rehi (2)
i==j: false
i equals j: true
i.value==j.value: true
========
i: new String(rehi (2)), j: not rehi
i==j: false
i equals j: false
i.value==j.value: false
========
i: new String(rehi (2)), j: new String("rehi")
i==j: false
i equals j: true
i.value==j.value: true
========
i: new String(rehi (2)), j: new String("not rehi")
i==j: false
i equals j: false
i.value==j.value: false
========
i: new String(rehi (2)), j: new String(rehi)
i==j: false
i equals j: true
i.value==j.value: true
========
i: new String(rehi (2)), j: new String(rehi (2))
i==j: true
i equals j: true
i.value==j.value: true
========
i: new String(rehi (2)), j: new String(not rehi)
i==j: false
i equals j: false
i.value==j.value: false
========
i: new String(not rehi), j: rehi
i==j: false
i equals j: false
i.value==j.value: false
========
i: new String(not rehi), j: rehi (2)
i==j: false
i equals j: false
i.value==j.value: false
========
i: new String(not rehi), j: not rehi
i==j: false
i equals j: true
i.value==j.value: true
========
i: new String(not rehi), j: new String("rehi")
i==j: false
i equals j: false
i.value==j.value: false
========
i: new String(not rehi), j: new String("not rehi")
i==j: false
i equals j: true
i.value==j.value: true
========
i: new String(not rehi), j: new String(rehi)
i==j: false
i equals j: false
i.value==j.value: false
========
i: new String(not rehi), j: new String(rehi (2))
i==j: false
i equals j: false
i.value==j.value: false
========
i: new String(not rehi), j: new String(not rehi)
i==j: true
i equals j: true
i.value==j.value: true
========
ответил Chris Dennett 21 MaramSun, 21 Mar 2010 09:26:06 +03002010-03-21T09:26:06+03:0009 2010, 09:26:06
0

Удивительно, что никто не ответил прямо на вопрос, но большинство ответов вызвало много голосов.

В двух словах: первая создает запись в String Pool, которую можно использовать повторно (более эффективно благодаря указанным выше ссылкам на неизменность, в основном, интернирование), а вторая создает новый объект String (более дорогой) ,

Оба объекта живут в куче. Ссылки на оба будут в стеке потока.

http://www.journaldev.com/797/what -is-java-string-pool дает четкое представление о том, как это достигается

ответил killjoy 31 MarpmTue, 31 Mar 2015 18:56:01 +03002015-03-31T18:56:01+03:0006 2015, 18:56:01
0

JVM выполняет некоторые хитрости при создании экземпляров строковых литералов для повышения производительности и уменьшения накладных расходов памяти. Чтобы сократить количество объектов String, созданных в JVM, класс String хранит пул строк. Каждый раз, когда ваш код создает строковый литерал, JVM сначала проверяет пул строкового литерала. Если строка уже существует в пуле, возвращается ссылка на объединенный экземпляр. Если строка не существует в пуле, создается новый объект String, а затем помещается в пул.

   public class Program
   {
       public static void main(String[] args)
       {
          String str1 = "Hello";  
          String str2 = "Hello"; 
          System.out.print(str1 == str2);
       }
   }

Вывод: true

К сожалению, когда вы используете

String a=new String("Hello");

Объект String создается из литерального пула String, даже если в пуле уже существует равная строка.

public class Program
{
    public static void main(String[] args)
    {
       String str1 = "Hello";  
       String str2 = new String("Hello");
       System.out.print(str1 == str2 );

    }
}

Вывод: ложь

ответил Yasir Shabbir Choudhary 16 Jpm1000000pmFri, 16 Jan 2015 23:07:32 +030015 2015, 23:07:32

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132