Java String类的不可变性

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_45505313/article/details/101446220

1. String 不可变的性质

如我们所知,String 对象通常被存在字符串常量池中,一旦一个 String 对象被创建出来,它就无法被修改。对 String 对象的所有修改操作其实都没有改变字符串本身的值,而是返回一个新的 String 对象

1.1 String 对象连接

从源码来看,String 的连接其实正如我们所知道的,不是在原 String 对象上添加字符串,而是将原字符串内容取出,重新组装一个 String 对象返回

public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }

在这里插入图片描述

1.2 String 不可变实现

String 不可变性质主要是依靠 final 关键字实现,源码的类声明和真正起到存储作用的字符数组的声明都使用到了 final

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];
    ......
}

另外可以看到,源码中对于字符数组 value 的操作都是通过深拷贝来完成的。赋值时是将传入数组保存的元素复制再写入 value 数组,读取时是将 value 数组的值取出再返回一个新的数组,保证了 value 数组的引用不会被外部持有。具体可参考 如何设计一个不可变类

// 赋值
public String(char value[]) {
        this.value = Arrays.copyOf(value, value.length);
}

// 读取
public char[] toCharArray() {
        // Cannot use Arrays.copyOf because of class initialization order issues
        char result[] = new char[value.length];
        System.arraycopy(value, 0, result, 0, value.length);
        return result;
}

2. String 不可变的目的

String 对象不可变其实具有多方面的原因,主要的考虑如下:

  1. 字符串常量池的实现
    只有当字符串是不可变的,字符串池才可能正确实现。字符串池的实现可以在运行时节约很多内存,因为不同的 字符串变量 可以指向池中的同一个字符串,避免了多个相同字符串对象的创建。如果字符串可变的话,当两个引用指向指向同一个字符串时,对其中一个做修改就会影响另外一个

在这里插入图片描述

  1. 安全性
    如果字符串是可变的,那么会引起很严重的安全问题。String 被广泛地充当参数使用,如网络连接、打开文件,甚至是类加载等操作。如果字符串可变,那么这些操作可能导致安全问题。比如某个方法使用字符串作为参数进行连接操作的时候,它认为自己已经连接到某台机器,但是实际上并没有(其他引用同一 String 对象的值修改会导致该连接中的字符串内容改变),这样就会对程序造成不可知的破坏

  2. 线程安全
    当字符串不可变时,天然就是多线程安全的,因为同一个字符串实例可以被多个线程共享,不用因为线程安全问题而使用同步

  3. 效率优化
    如果字符串是不可变的,在它创建的时候 hashcode 就可以被缓存,不需要重新计算。这就使得字符串很适合作为Map中的键,字符串的处理速度要快过其它的键对象

    /** Cache the hash code for the string */
     private int hash; // Default to 0
    

猜你喜欢

转载自blog.csdn.net/weixin_45505313/article/details/101446220