为什么Java中的字符串对象是不可变的?

不可变对象在创建后其内部状态无法改变,确保数据安全和完整性。Java的字符串被设计为不可变,以实现内存节省、线程安全和提高性能,如通过字符串常量池实现共享。此外,不可变对象在多线程环境中的使用避免了同步问题,且其hashcode会被缓存以优化集合操作。
摘要由CSDN通过智能技术生成

 何为不可变?  

        所谓不可变对象,是指一个对象在创建后,它的内部状态不会被改变的对象。换句话说,对象所包含的所有字段都是不可变的,任何对这些字段的修改都会导致一个新的对象被创建。这意味着当我们将一个不可变对象的引用赋值给某个变量后,我们就不能改变该对象的内部状态。 James Gosling也说过——Java开发者应该尽量使用不可变对象。

Java中所有的包装类都是不可变类 


不可变类的特点:

  1. 对象创建后其内部状态不能被修改。
  2. 所有字段都是 final 和 private 修饰的,防止未授权的访问和修改。
  3. 不提供修改内部状态的公共方法,只能通过构造器初始化或者提供查询方法来访问对象状态。
  4. 线程安全,可以在多线程环境下进行共享而无需担心同步问题。

不可变类的优点包括:

  1. 防止字段被修改,保证了数据的安全性和完整性。
  2. 不需要考虑并发风险,能够以更加简单、可靠的方式实现线程安全。
  3. 更容易缓存,由于不可变类对象的状态不会改变,因此可以通过缓存来提高应用程序的性能。


为什么字符串对象要设置为不可变?(好处是什么?)

节省内存        

        字符串常量池:字符串常量池是JVM中的一块特殊区域(1.7之前存放在perm区,1.8之后存放在堆上),用来存放字符串对象的值。在JVM中字符串是不可变的,因此JVM对于相同的字符序列,可以只保存一份,这个特性称之为“interning”。由于字符串是JVM中最常见的对象,因此实现字符串共享可以节省很多堆内存。

有两种方式定义的字符串,可以存放在常量池中:

  • 使用常量字符串初始化字符串变量
String s1 = "Hello World";
String s2 = "Hello World";
System.out.printlin(s1 == s2); //结果为true
  • 调用String对象的intern方法,需要注意的是:直接通过String的构造方法初始化的字符串对象,它的值并没有存放在字符串常量池,需要对该对象调用intern方法之后,才会将它的值放入字符串常量池。
String s1 = "Hello World";
String s2 = new String("Hello World");
System.out.println(s1 == s2); //结果为false

s2.intern();
System.out.println(s1 == s2); //结果为true

安全问题

        Java应用中使用字符串对象存放一些敏感信息:用户名、密码、连接地址、IP地址等等。Java中类加载器加载类的时候,也是根据类的名字去文件系统中的对应路径去查找的,类的名称、对应的路径,都是使用字符串对象存储的。

        将字符串对象设计为不可变的,就意味着这个敏感信息一经生成就不会被改变(有点现在流行的区块链的思路)。

常见的安全检查流程有两个步骤:

(1)校验安全信息; (2)进行敏感操作。如果字符串对象是可变的,则在做完第(1)步安全校验后这个字符串对象依然可能被改变。例如,我们现在在维护一个用户服务,提供了更改用户昵称的服务,业务逻辑是先检查用户昵称的合法性,然后再进行数据库的操作,如果字符串对象是可变的,那么第一步的合法性检查就没有意义了。


并发问题 

        不可变对象天然具备线程安全性,因为不用担心两个线程同时修改该对象时候产生的争用问题。假设字符串变量 str = "hello" 被多个线程同时使用,如果在某个线程中对str赋了新的字符串值,那么就会在字符串常量池中生成一份新的字符串,不会有并发争用。        


hashcode缓存 

        在Java集合框架的很多数据结构中都用到了字符串对象,例如HashMap、HashTable、HashSet等等,在这些数据结构的实现过程中,都使用hashcode()方法来进行hash操作。

        由于字符串对象的不变性,JDK将它的hashcode()做了缓存,这样对于同一个字符串对象,只会在第一次调用它的hashcode()方法的时候进行计算,后面的调用直接使用缓存中的值,这缓存也提升了集合数据结构的性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学徒630

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值