首先关于java传递值还是传递引用
可参见java到底传递值还是引用
结论是java传递的是值
接下来看看这个例子:
public class Test {
public static void main(String[] args) {
String b=new String("abc");
changeString(s);
System.out.println(s);
}
public static void changeString(String s)
{
s.toUpperCase();
}
}
输出:abc
我之前认为将string的引用传递到changString()函数中,对字符串的操作会改变引用所指位置的实际值。实际上这是另一个知识点。
不可变类
更多关于不可变类可以参考
如何写一个不可变类
如何使用建造者模式(Builder Pattern)创建不可变类
为什么Java要把字符串设计成不可变的
关于以上问题,传递的确实是string引用的拷贝(也就是值传递),但是因为String是不可变的,所以所有对其改变的操作都会新生成一个String对象,所以原来引用所指的值并没有改变。
“+”和StringBuilder
实例:
public class Test
{
public static void main(String[] args)
{
String s="test";
String result=s+"a"+"b"+"c";
System.out.println(result);
}
}
得到字节码:
public static void main(java.lang.String[]);
Code:
0: ldc #2 // String test
2: astore_1
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: aload_1
11: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: ldc #6 // String a
16: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: ldc #7 // String b
21: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: ldc #8 // String c
26: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
29: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
32: astore_2
33: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
36: aload_2
37: invokevirtual #11 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: return
从字节码中可以看出编译器对+进行了优化。
String不可变性除了有点外也会带来一定的效率问题。因为每次对string做个改变都会生成新的字符串。
看看另外的优化
实例:
public class Test
{
public static void main(String[] args)
{
String s="test";
String result="a"+"b"+"c";
System.out.println(result);
}
}
反编译字节码:
public static void main(java.lang.String[]);
Code:
0: ldc #2 // String test
2: astore_1
3: ldc #3 // String abc
5: astore_2
6: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
9: aload_2
10: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
13: return
对于这种字面量直接相加编译器直接将这些字面量合成一个字符串返回