浅谈string的不可改变性质和“+”拼接字符串

时间:2024-03-28 11:31:51

我们都知道String对象一旦创建就不可改变,那这是为什么呢?

那我们就从源代码入手,去分析String是如何维护其不可改变的性质。

手段一:final类和final的私有成员
浅谈string的不可改变性质和“+”拼接字符串
可以发现:
String是一个final类,且三个成员都是私有的,这就意味着String是不可被继承的,这样就可以防止出现程序猿通过继承重写String类的方法使得String类是“可变的”的情况。
每个String对象维护着一个char数组–>私有成员value。它是String的底层数组,用于存贮字符串的内容,而且是private final,但是数组是引用类型,所以只能限制引用不能改变而已。也就是说数组元素的值是可以改变的。

我们来做一个小实验:
浅谈string的不可改变性质和“+”拼接字符串
可以看到:字符串str使用数组arr来构造一个对象,当数组arr修改其元素值后,字符串str并没有跟着改变。

然后我们再看一下它的构造方法是怎么样的。
浅谈string的不可改变性质和“+”拼接字符串
可以看出:String在使用外部char数组构造对象的时候,是重新复制了一份外部char数组,从而不会让外部数组的改变影响到String对象

手段二:改变即创建对象的方法

浅谈string的不可改变性质和“+”拼接字符串
我们都是知道String有很多方法,这里以substring()为例,
可以看出,如果不是切割整个字符串的话,就会新建一个对象,也就是说,只要与原字符串不相等,就会新建一个String对象。这也就是在大量修改字符串的时候不建议使用String的原因,白白浪费内存。

既然说到string,就不得不说一说string的拼接字符串 “+”

先来看一个程序,看看不同情况下的输出:
浅谈string的不可改变性质和“+”拼接字符串
浅谈string的不可改变性质和“+”拼接字符串
s2的结果其实在编译期间就已经计算出来了(常量表达式的计算就是在编译期间完成的),与s1的值是一样的,所以在类加载时创建并维护在常量池中。但是s3的表达式含有变量s2,只能是运行时才能执行计算,也就是说在运行时才计算出他的结果,并且底层是new了一个StringBuilder对象,调用append()方法来实现拼接,所以它在堆中创建对象,s4就更不用讲了,直接在堆中new一个对象。

内存里的情况:
浅谈string的不可改变性质和“+”拼接字符串
从这里也就可以看出:当需要大量拼接字符串的时候,直接定义StringBuffer的对象,
直接调用append()方法去拼接就好了,不然就像s3一样会创建对象,这样也就浪费内存。