今天偶然看到 String 的源码,总结一下 String 不可变性。有些事情就是这样,就像自行车,几乎大家天天骑,但是知道自行车原理的人却很少。
先来讲讲,String 类的构造方法。一共有以下四种:
// 1. 第一种,使用字面量来创建字符串对象。
String str = "hello world";
//2. 使用构造函数:无参的构造函数或者带一个字符串的构造函数。
String str = new String();
String str = new String(字符串);
//3. 构造函数:带一个字符数组构造函数
char[] chars = {'a','b','c'};
String str = new String(chars);
//4. 带一个字节数组的构造函数。
byte[] bytes = ..
String str = new String(bytes);
这四种构造函数,有那些不同呢?请看下面的图:
图片.png
我堆上面的图做一下说明,
- 使用双引号创建的字符串,数值保存在堆中的常量池中。
- 使用构造函数创建的字符串对象,它的对象不在变量池中。
要谈 String 类的不可变性,需要谈到变量的“引用”和“值”
下面是个人的理解,引用是保存变量值的地址.
例如,abcd 是 s 的值,指向值“abcd”地址的别称
来自知乎
所以,只要值为“abc”的 String 变的引用都是相同的。也就是说
String str1 = "abc";
String str2 = "abc";
str1 == str2 // true
//
String str1 = "abc";
String str2 = new String("abc");
str1 == str2 // false
//
String str1 = new String("abc");
String str2 = new String("abc");
str1 == str2 // false
根据“引用”的性质,出现了上面不同的玩法。
自己想象出来的模型
- new 的方式是,无论“abcd”字段有无,jvm 都会在栈中新建一个对象。变量 str1、str2 的引用指向各自的对象地址。
- 赋值的方式不同的是 str2 也指向了 str1 的地址。
和“引用”性质相关的是函数的传值方式。Java 中函数的变量不是传的值,而是引用。所以在函数中是不能将传过来的 String 类型的值改变的。
例如
public String appendStr(String str){
str += "bbb";
return str ;
}
String a = new String("aaa")
appendStr(a)
System.out.println(a);// 结果是 aaa
- 对于对象而言,传的是对象引用的拷贝
- 所以在方法体内,是修改 str 的引用,a 的引用并没有修改
- 休闲代表修改 str 的引用之前的样子
大概就是这样吧
参考http://www.cnblogs.com/xiaoxi/p/6036701.html
这篇文章将 String 的不可变性、类中成员变量编译运行、final 属性、JVM 内存模型等结合在一起,将 String 类型的不可变性的各种情况说透。
文章中应该还缺少一些编译、运行的过程说明。