«Старый» способ выводит кучу StringBuilder
-ориентированных операций. Рассмотрим эту программу:
public class Example {
public static void main(String[] args)
{
String result = args[0] + "-" + args[1] + "-" + args[2];
System.out.println(result);
}
}
Если мы скомпилируем это с помощью JDK 8 или более ранней javap -c Example
версии, а затем воспользуемся им для просмотра байт-кода, мы увидим что-то вроде этого:
public class Example {
общедоступный пример ();
Код:
0: aload_0
1: invokespecial # 1 // Метод java / lang / Object. "<init>" :() V
4: возврат
public static void main (java.lang.String []);
Код:
0: новый # 2 // класс java / lang / StringBuilder
3: дубли
4: invokespecial # 3 // Метод java / lang / StringBuilder. "<init>" :() V
7: aload_0
8: iconst_0
9: аалоад
10: invokevirtual # 4 // Метод java / lang / StringBuilder.append: (Ljava / lang / String;) Ljava / lang / StringBuilder;
13: ldc # 5 // Строка -
15: invokevirtual # 4 // Метод java / lang / StringBuilder.append: (Ljava / lang / String;) Ljava / lang / StringBuilder;
18: aload_0
19: iconst_1
20: аалоад
21: invokevirtual # 4 // Метод java / lang / StringBuilder.append: (Ljava / lang / String;) Ljava / lang / StringBuilder;
24: ldc # 5 // Строка -
26: invokevirtual # 4 // Метод java / lang / StringBuilder.append: (Ljava / lang / String;) Ljava / lang / StringBuilder;
29: aload_0
30: iconst_2
31: аалоад
32: invokevirtual # 4 // Метод java / lang / StringBuilder.append: (Ljava / lang / String;) Ljava / lang / StringBuilder;
35: invokevirtual # 6 // Метод java / lang / StringBuilder.toString :() Ljava / lang / String;
38: astore_1
39: getstatic # 7 // Поле java / lang / System.out: Ljava / io / PrintStream;
42: aload_1
43: invokevirtual # 8 // Метод java / io / PrintStream.println: (Ljava / lang / String;) V
46: возврат
}
Как видите, он создает StringBuilder
и использует append
. Это известно довольно неэффективно, так как емкость встроенного буфера по умолчанию StringBuilder
составляет всего 16 символов, и компилятор не знает, как выделить больше заранее, поэтому ему приходится перераспределять. Это также набор вызовов методов. (Обратите внимание, что JVM иногда может обнаруживать и переписывать эти шаблоны вызовов, чтобы сделать их более эффективными.)
Посмотрим, что генерирует Java 9:
public class Example {
общедоступный пример ();
Код:
0: aload_0
1: invokespecial # 1 // Метод java / lang / Object. "<init>" :() V
4: возврат
public static void main (java.lang.String []);
Код:
0: aload_0
1: iconst_0
2: aaload
3: aload_0
4: iconst_1
5: аалоад
6: aload_0
7: iconst_2
8: аалоад
9: invokedynamic # 2, 0 // InvokeDynamic # 0: makeConcatWithConstants: (Ljava / lang / String; Ljava / lang / String; Ljava / lang / String;) Ljava / lang / String;
14: astore_1
15: getstatic # 3 // Поле java / lang / System.out: Ljava / io / PrintStream;
18: aload_1
19: invokevirtual # 4 // Метод java / io / PrintStream.println: (Ljava / lang / String;) V
22: возврат
}
О боже, но это короче. :-) Он выполняет единственный вызов makeConcatWithConstants
from StringConcatFactory
, в Javadoc которого говорится следующее:
Методы для облегчения создания методов конкатенации строк, которые можно использовать для эффективного конкатенации известного количества аргументов известных типов, возможно, после адаптации типа и частичной оценки аргументов. Эти методы обычно используются в качестве методов начальной загрузки для invokedynamic
сайтов вызовов для поддержки функции конкатенации строк языка программирования Java.