„Stary” sposób daje wiele StringBuilder
zorientowanych operacji. Rozważ ten program:
public class Example {
public static void main(String[] args)
{
String result = args[0] + "-" + args[1] + "-" + args[2];
System.out.println(result);
}
}
Jeśli skompilujemy to z JDK 8 lub wcześniejszym, a następnie użyjemy javap -c Example
do wyświetlenia kodu bajtowego, zobaczymy coś takiego:
klasa publiczna Przykład {
public Przykład ();
Kod:
0: aload_0
1: invokespecial # 1 // Metoda java / lang / Object. "<init>" :() V
4: powrót
public static void main (java.lang.String []);
Kod:
0: nowy # 2 // klasa java / lang / StringBuilder
3: dup
4: invokespecial # 3 // Metoda java / lang / StringBuilder. "<init>" :() V
7: aload_0
8: iconst_0
9: aaload
10: invokevirtual # 4 // Metoda java / lang / StringBuilder.append: (Ljava / lang / String;) Ljava / lang / StringBuilder;
13: ldc # 5 // Ciąg -
15: invokevirtual # 4 // Metoda java / lang / StringBuilder.append: (Ljava / lang / String;) Ljava / lang / StringBuilder;
18: aload_0
19: iconst_1
20: aaload
21: invokevirtual # 4 // Metoda java / lang / StringBuilder.append: (Ljava / lang / String;) Ljava / lang / StringBuilder;
24: ldc # 5 // Ciąg -
26: invokevirtual # 4 // Metoda java / lang / StringBuilder.append: (Ljava / lang / String;) Ljava / lang / StringBuilder;
29: aload_0
30: iconst_2
31: aaload
32: invokevirtual # 4 // Metoda java / lang / StringBuilder.append: (Ljava / lang / String;) Ljava / lang / StringBuilder;
35: invokevirtual # 6 // Metoda java / lang / StringBuilder.toString :() Ljava / lang / String;
38: astore_1
39: getstatic # 7 // Pole java / lang / System.out: Ljava / io / PrintStream;
42: aload_1
43: invokevirtual # 8 // Metoda java / io / PrintStream.println: (Ljava / lang / String;) V
46: powrót
}
Jak widać, tworzy a StringBuilder
i używa append
. Jest to znane jako dość nieefektywne, ponieważ domyślna pojemność wbudowanego bufora StringBuilder
wynosi tylko 16 znaków i nie ma możliwości, aby kompilator wiedział, aby przydzielić więcej z wyprzedzeniem, więc w końcu musi ponownie przydzielić. To także kilka wywołań metod. (Należy jednak pamiętać, że JVM może czasami wykrywać i przepisywać te wzorce wywołań, aby były bardziej wydajne).
Spójrzmy, co generuje Java 9:
klasa publiczna Przykład {
public Przykład ();
Kod:
0: aload_0
1: invokespecial # 1 // Metoda java / lang / Object. "<init>" :() V
4: powrót
public static void main (java.lang.String []);
Kod:
0: aload_0
1: iconst_0
2: aaload
3: aload_0
4: iconst_1
5: aaload
6: aload_0
7: iconst_2
8: aaload
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 // Pole java / lang / System.out: Ljava / io / PrintStream;
18: aload_1
19: invokevirtual # 4 // Metoda java / io / PrintStream.println: (Ljava / lang / String;) V
22: powrót
}
Ojej, ale to krócej. :-) Wykonuje pojedyncze wywołanie do makeConcatWithConstants
from StringConcatFactory
, które mówi w swoim Javadoc:
Metody ułatwiające tworzenie metod konkatenacji ciągów znaków, które można wykorzystać do skutecznego łączenia znanej liczby argumentów znanych typów, prawdopodobnie po dostosowaniu typu i częściowej ocenie argumentów. Metody te są zwykle używane jako metody ładowania początkowego w invokedynamic
witrynach wywołań w celu obsługi funkcji łączenia ciągów w języku programowania Java.