可变数据类型和不可变数据类型、String的不可变?

文章探讨了Java中的不可变数据类型如String和可变数据类型如StringBuilder的差异。不可变对象在多线程环境下更安全,适合共享,而可变对象如StringBuilder则允许修改,提高了效率。String的不可变性确保了线程安全、哈希码的唯一性和常量池的正确工作。StringBuffer是线程安全的可变字符串,适用于多线程环境。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

可变类型与不可变类型

不可变数据类型当该数据类型的变量的值发生了改变,那么它对应的内存地址也会发生改变,对于这种数据类型,就称为不可变数据类型。如java中基本数据类型以及String类

String S="abc";
s+="def";

当执行第一条语句后,S指向“abc”所在的内存地址0x01,执行完第二句之后S的值变为“abcdef”,此时S指向的对象所在的内存地址也变成了0x02; 

可变数据类型 当该数据类型的对应变量的值发生了改变,那么它对应的内存地址不发生改变,对于这种数据类型,就称为可变数据类型,当可变数据类型改变时它实际上是更改了内存中的内容。如StringBuilder,List,Set,Map。

StringBuilder S=new StringBuilder("a");
S.append("b");

 当S的值发生改变时,始终指向0x03这个地址。

优点

可变:由于对不可变数据类型进行修改会产生大量的临时拷贝,很占用空间,相比之下可变数据类型可以将拷贝最少化从而提高效率。

不可变:不可变对象是线程安全的,在线程之间可以相互共享;存在对一个对象的多次引用时,一般采用不可变类型。

String类型的不可变

首先需要补充一个容易混淆的知识点:当使用final修饰基本类型变量时,不能对基本类型变量重新赋值,因此基本类型变量不能被改变。但对于引用类型变量而言,它保存的仅仅是一个引用,final只保证变量所引用的地址不会改变,即一直引用同一个对象,但这个对象本身可以发生改变。

String类的两个主要成员变量:

                                private final char[] value;//用于存储字符串

                                private int hash; // Default to 0

其中value是变量,指向的是一个字符数组,字符串中的字符就是用这个value变量存储起来的,并且用final修饰,也就是说value一旦赋予初始值之后,value指向的地址就不能再改变了。但地址对应的内容是可以改变的。既然数组内容可变,那为什么String对象是不可变的呢? 

一个String对象被创建以后,包含这个对象中的字符串序列是不可改变的。

String a=”abc”;
String a=”bc”;

这里a变量发生了变化是因为a所指向的对象发生改变,“abc”对象本身没有改变。图中,指向1是可变的,指向2不可变。0x20实际上就是value指向的数组的地址,而value是由final修饰因此value指向的引用地址(0x20)不可变。但是0x20存储的内容是可以发生变化的。只是由于String类没有提供修改数组内容的方法所以造成String类型对象不可变。然而在StringBuilder中是提供了相应的方法让我们去修改value指向的数组的元素,这也是StringBuilder的字符串序列可变的原因。

为什么String类被设计成不可变?

String不可变的原因包括设计考虑,效率优化 ,以及安全性这三大方面。

常量池的需要 常量池的设计是为了优化性能,减少重复字符串的存储,而如果String对象的改变,会引起常量池的改变造成很多逻辑错误,增加损耗。 

String S1="gcc";
String S2="gcc";
String S3="gcc";

 由于S1、S2、S3全部指向常量池的同一个对象,如果字符串可变,修改S1指向的对象修改为“cc”,那么导致S2、S3全部被修改,这显然不符合编码逻辑。

允许String对象缓存HashCode:Java中String对象的哈希码被频繁地使用,字符串不变性保证了hash码的唯一性,因此可以放心地进行缓存。

安全性:String被许多的Java类(库)用来当做参数,例如网络连接地址URL、文件路径path,还有反射机制所需要的String参数等,,假若String不是固定不变的,将会引起各种安全隐患。

线程安全:因为字符串是不可变的,所以是多线程安全的,同一个字符串实例可以被多个线程共享。这样便不用因为线程安全问题而使用同步。字符串自己便是线程安全的。

String,StringBuffer, StringBuilder的区别是什么?

可变与不可变String类不可变;StringBuilder与StringBuffer这两种对象都是可变的。

是否线程安全String中的对象是不可变的,也就可以理解为常量,显然线程安全。StringBuilder是非线程安全的。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值