Чтобы помочь выяснить это, я написал класс, подобный следующему:
class Test {
String a = "abc" ;
StringBuilder buffer = new StringBuilder() ;
public void normal() {
buffer.append( "abc" ) ;
buffer.append( "abc" ) ;
}
public void clever() {
buffer.append( a ) ;
buffer.append( a ) ;
}
}
Если мы скомпилируем это, а затем запустим над ним javap, чтобы извлечь байт-код:
14:09:58 :: javap $ javap -c Test
Compiled from "Test.java"
class Test extends java.lang.Object{
java.lang.String a;
java.lang.StringBuilder buffer;
Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2; //String abc
7: putfield #3; //Field a:Ljava/lang/String;
10: aload_0
11: new #4; //class java/lang/StringBuilder
14: dup
15: invokespecial #5; //Method java/lang/StringBuilder."<init>":()V
18: putfield #6; //Field buffer:Ljava/lang/StringBuilder;
21: return
public void normal();
Code:
0: aload_0
1: getfield #6; //Field buffer:Ljava/lang/StringBuilder;
4: ldc #2; //String abc
6: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
9: pop
10: aload_0
11: getfield #6; //Field buffer:Ljava/lang/StringBuilder;
14: ldc #2; //String abc
16: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: pop
20: return
public void clever();
Code:
0: aload_0
1: getfield #6; //Field buffer:Ljava/lang/StringBuilder;
4: aload_0
5: getfield #3; //Field a:Ljava/lang/String;
8: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
11: pop
12: aload_0
13: getfield #6; //Field buffer:Ljava/lang/StringBuilder;
16: aload_0
17: getfield #3; //Field a:Ljava/lang/String;
20: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
23: pop
24: return
}
Мы можем видеть 2 вещи.
Во-первых, метод normal
использует один и тот же экземпляр String для обоих этих вызовов (в действительности это тот же литерал, который установлен для переменной-члена a
этого классав блоке инициализации)
А во-вторых, метод clever
длиннее, чем normal
.Это связано с тем, что для извлечения свойства из класса требуются дополнительные шаги.
Итак, мораль этой истории в том, что в 99% случаев Java делает все правильно, самостоятельно, и в этом нет необходимости.в попытке быть умным ;-) (а javap - действительно классный инструмент, когда вы хотите точно знать, что происходит)