Нет значения в Юлии

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
blockquote>

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, тогда результат строкового литерала является ссылкой на тот же экземпляр class String.
  • В противном случае создается новый экземпляр класса String, содержащий последовательность кодовых точек Unicode, заданную структурой CONSTANT_String_info; ссылка на этот экземпляр класса является результатом строкового литерала. Наконец, вызывается метод intern нового экземпляра String.
blockquote>

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."":(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)
  • struct указывает на CONSTANT_Utf8_info Structure , которая содержит данные. Это единственные необходимые данные для представления строки.

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

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

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

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

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

25
задан StefanKarpinski 11 June 2016 в 04:41
поделиться

0 ответов

Другие вопросы по тегам:

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