Java中的String类为什么不可变

柔光的暖阳◎ 2022-05-18 20:34 313阅读 0赞

1、什么是不可变?

java角度来讲就是说成final的。

String不可变如下图:

假设给字符串s赋值为abcd,第二次重新赋值为abcdef,这时候并不是在原内存地址上修改数据,而是重新指向一个新对象,新地址。

u_3996478173_2844988614_fm_173_s_0BA878230189C0EB58D4B5D60000C0B2_w_571_h_318_img.JPEG

2、String为毛不可变?

看源码的前3行你就懂了。

u_2225934376_1963760427_fm_173_w_518_h_74_img.JPEG

1、首先String类是用final修饰的,这说明String不可继承

2、其次String类的主力成员字段value是个char[]数组,而且是用final修饰的,final修饰的字段创建后就不可变。

注意:虽然value确实是final的,不可变了,但也只是value这个引用地址不可变,挡不住Array数组是可变的事实啊。

u_3709459685_3367133605_fm_173_s_6BA43C62AB8F58CA46F575DE0000C0B2_w_569_h_425_img.JPEG

也就是说Array变量只是stack上的一个引用,数组的本体结构在堆,String类的value属性用final修饰,只是说stack里的这个叫value的引用地址不可变,没有说堆里array本身数据不可变,如下的例子:

但如下是可以的

u_2158744127_1436105821_fm_173_w_437_h_47_img.JPEG

这时候明白了吧?

String不可变的关键不是一个final不可被继承,而是关键在于底层实现,value的修饰符private作用都比final大,再加上类是final的防止继承,避免被破坏。

3、不可变有什么好处呢?

两个字:安全

u_2451275907_1807406503_fm_173_s_04605532191A544D405D20DA0000C0B2_w_524_h_353_img.JPEG

结果:

可以发现String的值没有改变,这也正是他安全所在。

再看下载这个例子:

u_2262563165_2535326713_fm_173_s_015055320BD84441445520DE000080B2_w_485_h_199_img.JPEG

u_3532583295_2865505421_fm_173_w_528_h_52_img.JPEG

StringBuilder变量sb1和sb2分别指向了堆内存的字面量“abc”和“def”,把他们都插入一个HashSet,到这步没毛病。但后面我把变量sb3也指向sb1的地址,在改变sb3的值,因为StringBuilder没有不可变的保护。sb3直接在原先“abc”的地址上改,导致sb1的值也变了。这时候HashSet上就出现了两个相等的键值“abc123”。破坏了HashSet键值的唯一性,所以千万不要用可变类型做HashMap和HashSet键值

还有就是多个线程同时读取一个资源,是不会引发竟态条件的。只有对资源做写操作才会有危险,永不可变对象不能被写,所以线程安全。

最后别忘了String自带常量池的属性,如下

u_2248390402_2469185960_fm_173_s_0FA07C22AB974CCA1E5CA0DA000080B2_w_540_h_383_img.JPEG

堆内存只会有一块空间。节省内存空间,提高效率。

补充:https://blog.csdn.net/yuqi007163/article/details/53559864

发表评论

表情:
评论列表 (有 0 条评论,313人围观)

还没有评论,来说两句吧...

相关阅读