8 张图, 看懂 Java 字符串的不变性
字符串, 想必大家最熟悉不过了, 通常我们在代码中有几种方式可以创建字符串, 比如:
String s = "Hollis";
这时, 其实会在堆内存中创建一个字符串对象, 其中保存了一个字符数组, 该数组中保存了字符串的内容
上面的箭头可以理解为存储他的引用
当我们在代码中连续创建两个相同的字符串的时候, 其实会指向同一个对象因为当一个字符串被被创建的时候, 首先会去这个字符串池中查找, 如果找到, 直接返回对该字符串的引用
但是, 如果在程序中明确声明要新创建一个字符串的话是可以在堆上重新创建一个对象的如
String s = new String("Hollis")
接着, 我们来看两个字符串中常用的操作: 截取和连接会发生什么, 是在原来的字符串对象上修改还是重新创建字符串呢?
字符串的连接如
String s1 = s.concat("Chuang");
字符串的截取如
String s1 = s.substring(0, 2);
从上图中我们可以得到一个结论, 那就是字符串是不可变的, 无论发生什么操作, 一个已经创建好的字符串的内容不会被改变, 对它的任何类似修改的操作其实都是新生成了一个字符串对象
那么, 为什么要定义出不可变对象呢?
缓存 Hashcode
Java 中经常会用到字符串的哈希码 (hashcode) 例如, 在 HashMap 中, 字符串的不可变能保证其 hashcode 永远保持一致, 这样就可以避免一些不必要的麻烦这也就意味着每次在使用一个字符串的 hashcode 的时候不用重新计算一次, 这样更加高效
在 String 类中, 有以下代码: private int hash;
以上代码中 hash 变量中就保存了一个 String 对象的 hashcode, 因为 String 类不可变, 所以一旦对象被创建, 该 hash 值也无法改变所以, 每次想要使用该对象的 hashcode 的时候, 直接返回即可
使其他类的使用更加便利
在介绍这个内容之前, 先看以下代码:
在上面的例子中, 如果字符串可以被改变, 那么以上用法将有可能违反 Set 的设计原则, 因为 Set 要求其中的元素不可以重复上面的代码只是为了简单说明该问题, 其实 String 类中并没有 value 这个字段值
安全性
String 被广泛的使用在其他 Java 类中充当参数比如网络连接打开文件等操作如果字符串可变, 那么类似操作可能导致安全问题因为某个方法在调用连接操作的时候, 他认为会连接到某台机器, 但是实际上并没有 (其他引用同一 String 对象的值修改会导致该连接中的字符串内容被修改) 可变的字符串也可能导致反射的安全问题, 因为他的参数也是字符串
不可变对象天生就是线程安全的
因为不可变对象不能被改变, 所以他们可以自由地在多个线程之间共享不需要任何同步处理
总之, String 被设计成不可变的主要目的是为了安全和高效所以, 使 String 是一个不可变类是一个很好的设计
来源: https://mp.weixin.qq.com/s?__biz=MzI3NzE0NjcwMg==&mid=2650120692&idx=1&sn=b96e61fa320c4b346e19515f071f2de6&chksm=f36bbcd5c41c35c36a11aefdee6b86c584c528e47a235ae1b94fca3c6b9b1491536c0fcfccaa&scene=38#wechat_redirect