不可变的String
String对象是不可变的。 String类中每一个看起来会修改String值的方法,实际上都是创建了一个全新的String对象,以包含修改后的字符串内容
String str1 = "java";
String str2 = "java";
System.out.println\("str1=str2 " + \(str1 == str2\)\);
在代码中,可以创建同一个String对象的多个别名,而它们所指的对象是相同的,一直待在一个单一的物理位置上
重载“+”
在Java中,唯一被重载的运算符就是用于String的“+”与“+=”。除此之外,Java不允许程序员重载其他的运算符
public class StringTest {
String a = "abc";
String b = "mongo";
String info = a + b + 47;
}
String对象是不可变的,所以在上述的代码过程中可能会是这样工作的:
- "abc" + "mongo"创建新的String对象abcmongo;
- "abcmongo" + "47"创建新的String对象abcmongo47;
- 引用info 指向最终生成的String;
但是这种方式会生成一大堆需要垃圾回收的中间对象,性能相当糟糕
编译器的优化处理
Compiled from "StringTest.java"
public class StringTest {
java.lang.String a;
java.lang.String b;
java.lang.String info;
public StringTest();
Code:
0: aload_0
1: invokespecial #12 // Method java/lang/Object."<init>":
()V
4: aload_0
5: ldc #14 // String abc
7: putfield #16 // Field a:Ljava/lang/String;
10: aload_0
11: ldc #18 // String mongo
13: putfield #20 // Field b:Ljava/lang/String;
16: aload_0
17: new #22 // class java/lang/StringBuilder
20: dup
21: aload_0
22: getfield #16 // Field a:Ljava/lang/String;
25: invokestatic #24 // Method java/lang/String.valueOf:(
Ljava/lang/Object;)Ljava/lang/String;
28: invokespecial #30 // Method java/lang/StringBuilder."<
init>":(Ljava/lang/String;)V
31: aload_0
32: getfield #20 // Field b:Ljava/lang/String;
35: invokevirtual #33 // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
38: bipush 47
40: invokevirtual #37 // Method java/lang/StringBuilder.ap
pend:(I)Ljava/lang/StringBuilder;
43: invokevirtual #40 // Method java/lang/StringBuilder.to
String:()Ljava/lang/String;
46: putfield #44 // Field info:Ljava/lang/String;
49: return
}
反编译以上代码会发现,编译器自动引入了StringBuilder类。
编译器创建了一个StringBuilder对象,并调用StringBuilder.append()方法,最后调用toString()生成结果,从而避免中间对象的性能损耗,即String对"+"的支持,实际上是使用StringBuilder的append以及toString
说明:Java 语言提供对字符串串联符号("+")以及将其他对象转换为字符串的特殊支持。字符串串联是通过 StringBuilder(或 StringBuffer)类及其 append 方法实现的。字符串转换是通过toString方法实现的,该方法由 Object类定义,并可被Java中的所有类继承