1."不可变"的一个例子
给一个已有字符串"abcd"第二次赋值成"abcedl",不是在原内存地址上修改数据,而是重新指向一个新对象,新地址。
2.JDK源码说明
public final class String implements Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
...
}
String类用final关键字修饰,说明其不可继承。
3.为什么要不可变?
1.当初始化一个字符串变量时,如果字符串已经存在,就不会创建一个新的字符串变量,而是返回存在字符串的引用。 例如: String s1=“abcd”; String s2=“abcd”; 这两行代码在堆中只会创建一个字符串对象。如果字符串是可变的,改变另一个字符串变量,就会使另一个字符串变量指向错误的值。
让我们来比较一下String和StringBuilder:
class Test{
//不可变的String
public static String appendStr(String s){
s+="bbb";
return s;
}
//可变的StringBuilder
public static StringBuilder appendStr(StringBuilder sb){
return sb.append("bbb");
}
public static void main(String[] args) {
//String做参数
String s = "aaa";
String ns = Test.appendStr(s);
System.out.println("String aaa >>"+s.toString());
//StringBuilder做参数
StringBuilder sb = new StringBuilder("aaa");
StringBuilder nsb = Test.appendStr(sb);
System.out.println("String aaa >>"+sb.toString());
}
}
2.字符串的hashcode是经常被使用的,字符串的不变性确保了hashcode的值一直是一样的,在需要hashcode时,就不需要每次都计算,这样会很高效。
3.字符串经常作为网络连接、数据库连接等参数,不可变就可以保证连接的安全性。
4.值传递和引用传递
1.基本数据类型,传递的是数据的拷贝 。“值传递”,在这种方式下,被调用对象对新数据的改变不影响源数据的取值,如基本类型的传递。
void method1(){
int x=0;
this.change(x);
System.out.println(x);
}
void change(int i){
i=1;
}
output:x=0
2.引用数据类型,传递的是传递的引用地址的拷贝,而不是该对象本身 。被调用对象新数据的改变影响源数据内容,因为新数据和源数据的引用虽然不同但却指向同一数据对象,如类型对象的传递。
void method2(){
StringBuffer x=new StringBuffer("Hello");
this.change(x);
System.out.println(x);
}
void change(StringBuffer i){
i.append(" world!");
}
output:x=Hello world!
2.String是一个比较特殊的数据类型,在Java中,String是一个类,但是他的传值却是采用“值传递”的方式。 String不属于8种基本数据类型,String是一个对象。
void method3(){
String x="a";
this.change(x);
System.out.println(x);
}
void change(String s){
s=s+"b";
System.out.println(s);
}
output:
x=a ;
s=ab
参考链接:
https://www.zhihu.com/question/20618891 来自胖胖的回答
http://blog.csdn.net/yanlove_jing/article/details/51396255