Как конкатенация окончательных строк выполняется на Java?

Когда я компилирую этот фрагмент.

public class InternTest {
    public static void main(String...strings ){
        final String str1="str";
        final String str2="ing";
        String str= str1+str2;

    }
}

Что создает следующий байтовый код

public static void main(java.lang.String...);
   flags: ACC_PUBLIC, ACC_STATIC, ACC_VARARGS
   Code:
     stack=1, locals=4, args_size=1
        0: ldc           #16                 // String str
        2: astore_1
        3: ldc           #18                 // String ing
        5: astore_2
        6: ldc           #20                 // String string
        8: astore_3
        9: return

поэтому строковая литерал "string" уже присутствует в пуле констант, который нажимается на 6: ldc #20 // String string на стеке в этой строке.

Цитирование JSL

Из JLS §4.12.4 - окончательные переменные:

Переменная примитивного типа или типа String, которая является окончательной и инициализированное выражением константы времени компиляции (§15.28), является называемой постоянной переменной.

Также из JLS §15.28 - ConstantExpression:

Выражения константы времени компиляции типа String всегда "интернированы" чтобы обмениваться уникальными экземплярами, используя метод String # intern().

Итак, я знаю, что str1 и str2 будут интернированы с момента его создания. "str" и "ing" будут иметь одну и ту же память в строке String str= str1+str2; Но как str1 + str2 напрямую создает строку в пуле строк. Без вызова любого класса String Builder, как это происходит, когда я не пишу final.? Чтобы узнать, есть ли у него какие-либо действия в отношении стажеров.

Я написал этот фрагмент

public class IntermTest {
    public static void main(String...strings ){
         String str1=("str").intern();
        String str2=("ing").intern();
        String str= str1+str2;

    }
}

Но когда я сгенерировал байтовый код, я получил этот

public static void main(java.lang.String...);
    flags: ACC_PUBLIC, ACC_STATIC, ACC_VARARGS
    Code:
      stack=3, locals=4, args_size=1
         0: ldc           #16                 // String str
         2: invokevirtual #18                 // Method java/lang/String.intern:
()Ljava/lang/String;
         5: astore_1
         6: ldc           #24                 // String ing
         8: invokevirtual #18                 // Method java/lang/String.intern:
()Ljava/lang/String;
        11: astore_2
        12: new           #26                 // class java/lang/StringBuilder
        15: dup
        16: aload_1
        17: invokestatic  #28                 // Method java/lang/String.valueOf
:(Ljava/lang/Object;)Ljava/lang/String;
        20: invokespecial #32                 // Method java/lang/StringBuilder.
"<init>":(Ljava/lang/String;)V
        23: aload_2
        24: invokevirtual #35                 // Method java/lang/StringBuilder.
append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        27: invokevirtual #39                 // Method java/lang/StringBuilder.
toString:()Ljava/lang/String;
        30: astore_3
        31: return

В действительности он также использует stringBuilder для конкатенации. Так что он сделал что-то с финалом. Есть ли что-то особенное в строках final, о которых я точно не знаю?

Ответы

Ответ 1

http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.28 говорит, что

Простые имена (§6.5.6.1), которые относятся к постоянным переменным (§4.12.4), являются постоянными выражениями.

http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.28 также говорит:

Постоянное выражение представляет собой выражение, обозначающее значение примитивного типа или String, которое не завершается внезапно и составлено с использованием только следующего:

  • Литералы примитивного типа и литералы типа String (§3.10.1, §3.10.2, §3.10.3, §3.10.4, §3.10.5)
  • [...]
  • Аддитивные операторы + и - (§15.18)
  • [...]
  • Простые имена (§6.5.6.1), которые относятся к постоянным переменным (§4.12.4).

Пример 15.28-1. Константные выражения

[...]

"Целое число + Long.MAX_VALUE +" очень велико. "

Поскольку эти две переменные являются постоянными выражениями, компилятор делает конкатенацию:

String str = str1 + str2;

скомпилируется так же, как

String str = "str" + "ing";

который скомпилирован так же, как

String str = "string";