String的不变性
英文版:https://www.programcreek.com/2009/02/diagram-to-show-java-strings-immutability/
中文版:https://www.hollischuang.com/archives/1230JDK6和JDK7中的substring的原理及区别
英文版:https://www.programcreek.com/2013/09/the-substring-method-in-jdk-6-and-jdk-7/
中文版:https://www.hollischuang.com/archives/1232String对“+”的重载
为什么不建议使用+连接字符串呢,看如下代码:
public void testString() {
String a = "temp";
for (int i = 0; i < 10; i++) {
a += i;
}
}
javap -c Test.class
public void testString();
Code:
0: ldc #2 // String temp
2: astore_1
3: iconst_0
4: istore_2
5: iload_2
6: bipush 10
8: if_icmpge 36
11: new #3 // class java/lang/StringBuilder
14: dup
15: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
18: aload_1
19: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: iload_2
23: invokevirtual #6 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
26: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
29: astore_1
30: iinc 2, 1
33: goto 5
36: return
可以从字节码中看出满足循环条件,从5处开始每次使用+,就会new一个StringBuilder对象,然后使用StringBuilder.append(),最后再用toString()转换,这样就会创建很多没有必要的StringBuilder对象,增加系统开销。
- Java 7中switch支持String
public void testSwitch() {
String test = "test";
switch (test) {
case "t":
System.out.println("t");
break;
default:
System.out.println("default");
}
}
查看字节码
Code:
0: ldc #2 // String test
2: astore_1
3: aload_1
4: astore_2
5: iconst_m1
6: istore_3
7: aload_2
8: invokevirtual #3 // Method java/lang/String.hashCode:()I
11: lookupswitch { // 1
116: 28
default: 39
}
28: aload_2
29: ldc #4 // String t
31: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
34: ifeq 39
37: iconst_0
38: istore_3
39: iload_3
40: lookupswitch { // 1
0: 60
default: 71
}
60: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
63: ldc #4 // String t
65: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
68: goto 79
71: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
74: ldc #8 // String default
76: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
79: return
从8处可以看出,switch(test)执行的是String.hashCode(),即switch(hashCode值),可以查看String的源码,hashCode()返回的是int类型,switch其实就是对整型支持。case "t" 即是31处"t".equals(test)
延伸-switch对枚举的支持
public class TestEnum {
public static void main(String[] args) {
Type type = Type.NUMBER;
switch (type) {
case NUMBER:
System.out.println("number");
case STRING:
System.out.println("string");
}
}
}
enum Type {
NUMBER,
STRING
}
查看字节码
Compiled from "TestEnum.java"
public class demo.TestEnum {
public demo.TestEnum();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field demo/Type.NUMBER:Ldemo/Type;
3: astore_1
4: getstatic #3 // Field demo/TestEnum$1.$SwitchMap$demo$Type:[I
7: aload_1
8: invokevirtual #4 // Method demo/Type.ordinal:()I
11: iaload
12: lookupswitch { // 2
1: 40
2: 48
default: 56
}
40: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
43: ldc #6 // String number
45: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
48: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
51: ldc #8 // String string
53: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
56: return
}
从12处可以看出,枚举值对应成顺序整数,也再次印证我们之前说的,switch其实就是对整型的支持。
Compiled from "TestEnum.java"
class demo.TestEnum$1 {
static final int[] $SwitchMap$demo$Type;
static {};
Code:
0: invokestatic #1 // Method demo/Type.values:()[Ldemo/Type;
3: arraylength
4: newarray int
6: putstatic #2 // Field $SwitchMap$demo$Type:[I
9: getstatic #2 // Field $SwitchMap$demo$Type:[I
12: getstatic #3 // Field demo/Type.NUMBER:Ldemo/Type;
15: invokevirtual #4 // Method demo/Type.ordinal:()I
18: iconst_1
19: iastore
20: goto 24
23: astore_0
24: getstatic #2 // Field $SwitchMap$demo$Type:[I
27: getstatic #6 // Field demo/Type.STRING:Ldemo/Type;
30: invokevirtual #4 // Method demo/Type.ordinal:()I
33: iconst_2
34: iastore
35: goto 39
38: astore_0
39: return
Exception table:
from to target type
9 20 23 Class java/lang/NoSuchFieldError
24 35 38 Class java/lang/NoSuchFieldError
}
ps:字节码真是个好东西,原来好多不懂的原理,都可以通过字节码看出个一二三来。