String不可变性

什么是不可变类?

这样理解:
一个对象在创建完成后,不能去改变它的状态,不能改变它的成员变量(如果成员变量包含基本数据类型,那么这个基本数据类型的值不能改变;如果包含引用类型,那么这个引用类型的变量不能指向别的对象)

String类

源码

 

arduino

复制代码

public final class String implements java.io.Serializable, Comparable<String>, CharSequence { // value 数组被 final 修饰 private final char value[]; ... }

我们可以看到有两点:

  • String是一个final类它不能被其他类继承
  • String类存放字符串内容是因为它具有char类型的value[]属性,被 final 修饰,表示字符串一旦被创建,就不可修改

final修饰引用类型,它保存的仅仅是一个引用,final只保证这个引用类型变量所引用的地址不会改变,也就是一直引用同一个对象,但这个对象完全可以发生改变。

拿下面的例子来说,char类型的数组被final修饰,表示value不可指向新的数组但是当前数组里面的值是可变的。

可以看出修改数组中的值是可以的,但是让当前变量指向新数组时会报错

String内存图

字面量赋值

 

ini

复制代码

String str="Hello";

先从常量池查看是否有"Hello"数据空间,如果有则直接指向;如果没有则重新创建,然后指向str最终指向的是常量池的空间地址**【jdk1.7以及之后版本字符串常量池在堆中,具体看这篇文章】**

通过构造器

 

ini

复制代码

String str2=new String("Hello");

先在堆中创建空间,里面具有value属性,指向常量池的"Hello"空间。如果常量池没有"Hello",重新创建,如果有则直接通过value指向。最终指向的是堆中的空间地址。 根据以上的创建过程,不难看出方式一是直接指向常量池中的字符串常量,方式二则是先指向堆中,然后根据堆中的地址指向常量池中的字符串常量

String不可变的本质

我们知道被 final 关键字修饰的类不能被继承,修饰的方法不能被重写,修饰的变量是基本数据类型则值不能改变,修饰的变量是引用类型则不能再指向其他对象。因此,final 关键字修饰的数组保存字符串并不是 String 不可变的根本原因,因为这个数组保存的字符串是可变的(final 修饰引用类型变量的情况)。 String 真正不可变有下面几点原因: 

  1. 保存字符串的数组被 final 修饰且为私有的,并且String 类没有提供/暴露修改这个字符串的方法。
  2.  String 类被 final 修饰导致其不能被继承,进而避免了子类破坏 String 不可变

解惑

这时就有人疑惑了:为什么 String 不可变?但我的代码中经常改变 String 啊,如下:

 

ini

复制代码

String str = "HELLO"; str = "WORLD"; System.out.println(str); // WORLD

虽然字符串的内容看上去从“HELLO” 变成了“WORLD”,但实际上,这已经是生成了一个新的字符串了: 

 

ini

复制代码

String str = "HELLO"; System.out.println(str.hashCode()); // 68624562 str = "WORLD"; System.out.println(str.hashCode()); // 82781042

变量 str 前后的 hashCode 值不一样,说明了 str 在改变前后,指向了不同的对象。所以,变量 str 只是指向了不同对象,字符串 “HELLO”对象本身没有被改变。

作者:蓝色记忆
链接:https://juejin.cn/post/7242720768885997623
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值