Java中String不可变性的本质

什么是字串的不可变性?

导论

在回答这个问题之前,我们先来看下String类的一些相关知识,这是我们常见的String用法:

String str = "knowledge";

这段代码的逻辑如下,创建一个字符串常量 knowledge,然后字符串地址赋给一个字串引用str,足够简单吧。别急,让我们来点稍微复杂一点的:

 String s = str; 

这段代码创建了一个新的字串引用,并将其指向字符串常量 “Knowledge” ,好了我们看下下面这段代码究竟做了什么:

 str = str.concat(" base");

首先,从功能实现上讲,代码做了一个字串拼接操作,字串 base 拼接到 str 后面,并重新赋予 str,,但这时,你心里可能不免疑惑 **:**String字串不是不可变的么?为什么还可以这么操作而不发生错误?OK,为了回答你的疑惑,我们来看下这段代码背后,JAVA虚拟机究竟做了什么?

当这段代码执行的时候,JVM首先读取str的值 “Knowledge”(注意,我们前面说了,str其实是一个字串引用,只不过这个引用本身指向的是内存中一块特殊的地址,地址上存储的是字符串常量 Knowledge),然后执行字串拼接操作,得到一个新的字串 “ Knowledge base” ,新的字串同样会存在内存中一块特殊的 内存区域(后续讨论)中,我们知道String是不可变的,我们不可能在原来的内存地址上覆盖新的字串,而是新开辟了一段内存地址存储我们得到的新的字串内容,并且同时将这个地址重新指向字串引用str。

至此,我们要特别注意一点:字串本身 (比如:“Knowledge”)是不可变的,但是,字串引用(比如:str)是可变的,一个字串本身可以有多个字串引用,换句话说,即允许存在多个字串引用指向同一个内存地址。

让我们重新回到上面的代码,这段代码其实产生了共总三个字符串常量对象: “Knowledge”,“ base”,“Knowledge base”以及两个字串引用 s 以及 str, 其中s指向的是 “Knowledge” ,而str指向的是 “Knowledge base”

字串使用与内存管理

继续上面的问题,假设我们代码中没有任何引用指向字串 “Knowledge”,是不是这个字串就凭空消失了?答案:否,事实上它依旧存在,但因为没有任何引用指向它,所以我们可以认为它“消失”了。我们再看一个例子:

String s1 = "java";
s1.concat(" rules");
System.out.println("s1 refers to "+s1);  // Yes, s1 still refers to "java"

这段代码做了什么?

  • 第一行非常简单:创建一个字串常量 “Java” ,并将引用s1指向它。

  • 接下来,虚拟机创建了新的字串 “Java rules”, 但因为没有任何引用指向它,字串 “Java rules”“ 即可 消失了,我们也找不到它了。而引用s1呢依旧指向字串 “Java”

在我们日常的编码实践中,几乎每一个用到String字串的方法都会包含修改或创建字串对象的场景,那么这些字串究竟去哪了呢?答案是它们仍旧在内存中。作为一个码农,我们知道,无论哪一种编程语言,无不例外都期最高效的利用计算机内存,以到达“牛逼哄哄”的境界。

对于Java语言来说,随着应用程序的不断增长,一个潜在的影响就是越来越多的字串常量可能会占据越来越多的内存区域,进而导致整个程序的内存溢出。因此,为了解决这个潜在的问题,避免内存使用无限增长,JVM特意开辟了一段特殊的内存区域来存放这些字串常量,这段内存区域就是我们说的“字符串常量池 ”- String constant pool

当Java虚拟机需一个字串常量时,它首先会去内存中 “字符串常量池”中去找是否有这样的字串常量,如果存在,那么字串本身就会新增一个字串引用,而不是新建一个全新的字串,对于常量池中的字串本身来说,其无非是多了一个字串引用而已,接下来,我们来回答文章开头的问题,什么是字串的不可变性:

“字符串常量池”中,一个字串常量可能包含不止一个的字串引用,即同时存在多个字串应用指向它,各个引用本身之间可能互不相识,也即是说彼此可能并不知道对方的存在,假设允许存在 其中一个字串引用“不小心”修改了字串常量的值,那很可能会出现“ 你大爷还是你大爷,你大妈已不是你原来的大妈了”的场景,这就是字串对象的不可变性。

那或许有人会说了,如果我可以覆盖(Override)String类定义实现啊,不一样会修改字串对象么?放心,已经有人替你想到了,String类从一开始就被设计是final类型的,所以没有任何人可以覆盖其定义实现的。

 _*_ _@since_ _ **JDK1.0**
__*/_
 public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {

完结

https://stackoverflow.com/questions/8798403/string-is-immutable-what-exactly-is-the-meaning

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值