“哥,你让我看的《Java 开发手册》上有这么一段内容:循环体内,拼接字符串最好使用 StringBuilder 的 append()
方法,而不是 + 号操作符。这是为什么呀?”三妹疑惑地问。
“其实这个问题,我们之前在 StringBuilder 时已经聊过了。”我慢吞吞地回答道,“不过,三妹,哥今天来给你深入地讲讲。”
PS:三妹能在学习的过程中不断地发现问题,让我感到非常的开心。其实很多时候,我们不应该只是把知识点记在心里,还应该问一问自己,到底是为什么,只有迈出去这一步,才能真正的成长起来。
+号操作符的本质
“+ 号操作符其实被 Java 在编译的时候重新解释了,换一种说法就是,+ 号操作符是一种语法糖,让字符串的拼接变得更简便了。”一边给三妹解释,我一边在 Intellij IDEA 中敲出了下面这段代码。
class Demo {
public static void main(String[] args) {
String chenmo = "沉默";
String wanger = "王二";
System.out.println(chenmo + wanger);
}
}
在 Java 8 的环境下,使用 javap -c Demo.class
反编译字节码后(字节码和 javap 我们会在 JVM 中详细讲,这里可以硬着头皮瞄一眼),可以看到以下内容:
Compiled from "Demo.java"
class Demo {
Demo();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #2 // String 沉默
2: astore_1
3: ldc #3 // String 王二
5: astore_2
6: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
9: new #5 // class java/lang/StringBuilder
12: dup
13: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V
16: aload_1
17: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
20: aload_2
21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
27: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: return
}
(如果你之前没有了解过字节码指令,可能会有一点压力,不过,不用担心,我们稍微解释一下就懂了)
“你看,三妹,这里有一个 new 关键字,并且 class 类型为 java/lang/StringBuilder
。”我指着标号为 9 的那行对三妹说,“这意味着新建了一个 StringBuilder 的对象。”
“然后看标号为 17 的这行,是一个 invokevirtual 指令,用于调用对象的方法,也就是 StringBuilder 对象的&n