细思极恐的 String 不可变属性

今天偶然看到 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

我堆上面的图做一下说明,

  1. 使用双引号创建的字符串,数值保存在堆中的常量池中。
  2. 使用构造函数创建的字符串对象,它的对象不在变量池中。

要谈 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 类型的不可变性的各种情况说透。
文章中应该还缺少一些编译、运行的过程说明。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容