- 类、方法、变量尽量指定fina修饰;
- 字符串拼接背后不一定是StringBuilder,还可能发生了编译时替换;
- 用final修饰的字符串在拼接时,在编译的时候会发生编译时替换,直接替换成常量,而不用拼接;
使用final修饰String字节码分析
- 由于x和y都使用final修饰,在z的赋值中也是直接将常量压栈然后赋值的;
/**
0: ldc #8 // String hello
2: astore_0
3: ldc #46 // String helloworld
5: astore_1
6: ldc #48 // String hellohelloworld
8: astore_2
9: getstatic #31 // Field java/lang/System.out:Ljava/io/PrintStream;
12: aload_2
13: invokevirtual #37 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
16: return
* */
public static void f1() {
final String x="hello";
final String y=x+"world";
String z=x+y;
System.out.println(z);
}
不使用final修饰String字节码分析
- 由于只有x用final修饰,虽然y的复制还是从常量池压栈赋值,但是z的赋值却new了一个StringBuilder,调用了append()方法;
/**
0: ldc #19 // String hello
2: astore_1
3: ldc #21 // String helloworld
5: astore_2
6: new #42 // class java/lang/StringBuilder
9: dup
10: ldc #19 // String hello
12: invokespecial #44 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
15: aload_2
16: invokevirtual #46 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #50 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: astore_3
23: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;
26: aload_3
27: invokevirtual #31 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: return
* */
public void f2(){
final String x="hello";
String y=x+"world";
String z=x+y;
System.out.println(z);
}
编译时替换示例
- 因为lo没有用final修饰,所以第4次比较没有发生编译时替换;
- 关于intern():如果调用的时候,常量池中有这个字符串,就将常量池中的字符串返回;
public class StringLiteral {
public static class Other {
public static String hello = "Hello";
}
public static void main(String[] args) {
String hello = "Hello", lo = "lo";
System.out.println(hello == "Hello");
System.out.println(Other.hello == hello);
System.out.println(hello == "Hel"+ "lo");
System.out.println(hello == ("Hel"+ lo));
System.out.println(hello == ("Hel"+ lo).intern());
}
}
输出:
true
true
true
false
true
intern()示例
- s.intern(); 常量池中已经有了"1",什么也不做,s还是指向堆;
- s2指向常量池中的"1";
- s3指向堆中的"11";
- s3.intern(); 常量池中没有"11",从而常量池中多了一个指向堆中"11"的引用;
- s4通过常量池指向堆中的"11";
public class AboutIntern {
public static void main(String[] args) {
String s = new String("1");
s.intern();
String s2 = "1";
System.out.println(s == s2);
System.out.println(s.intern() == s2);
String s3 = new String("1") + new String("1");
s3.intern();
String s4 = "11";
System.out.println(s3 == s4);
}
}
输出:
false
true
true