Java String为什么是不可变的

一: 什么是不可变

如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的。

二: String内部构成

    /** The value is used for character storage. */
    private final char value[];

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

实质上,String的底层是char[]数组,其存储关系为:字符串对象的引用 -->  字符串对象  --> char数组对象

调用图来自:https://blog.csdn.net/zhangjg_blog/article/details/18319521

三: String方法返回大部分是新的字符串,而不是改变了字符串的内容,从黄色部分可以看出。

    public String replace(char oldChar, char newChar) {
        if (oldChar != newChar) {
            int len = value.length;
            int i = -1;
            char[] val = value; /* avoid getfield opcode */

            while (++i < len) {
                if (val[i] == oldChar) {
                    break;
                }
            }
            if (i < len) {
                char buf[] = new char[len];
                for (int j = 0; j < i; j++) {
                    buf[j] = val[j];
                }
                while (i < len) {
                    char c = val[i];
                    buf[i] = (c == oldChar) ? newChar : c;
                    i++;
                }
                return new String(buf, true);
            }
        }
        return this;
    }

四: String为什么要设计成不变

1-为了安全,也是最重要的原因

举个HashSet的应用:

Set<String> sets = Sets.newHashSet();
String s1 = "aaa";
sets.add(s1);
sets.add("bbb");

String s2 = s1;
s2 = "bbb";
sets.add(s2);

很简单sets集合的包含两个元素,“aaa” 和 “bbb”,自然size==2;

想一下,如果String是不可变的,元素就变成了“bbb” 和“bbb”,size==2;这样的结果显然是不正确的。

当然高并发也是有问题的。

2- 节约内存空间

都知道String是存储到常量池中的,每个String对象都是不可变的,这样就不存在修改(写)对象的情况,也就不存在高并发读取有误的安全问题。每个String都可以同时被多个线程调用。自然就节省了内存空间;

试想,如果String是可变的,为了保证安全性,会创建很多相同内容的对象,也就造成了不必要的浪费;

3-减少重复性计算

仍然拿HashSet集合举例,其HashSet的key是存储的hashcode值。String对象不变,其hashcode值就不会改变,也就不用每次调用hashSet进行重新计算。

五: String真的是不可变的吗

String对象内容实质是char[]数组,char[]为引用变量,而不是真正的对象。即使被final修饰,也只能说明不能改变其引用。然而实际上char[]还是可以改变的。

    private static final char[] chars = {'a','a','a','a','a','a'};
    public static void main(String[] args){
        chars[0] = 'b';
        System.out.println(chars);
    }

输出结果:baaaaa

大家可能还要说,有private修饰呀。

这个可以用反射进行修改;所以说String不是实质上的不可变;

参考文献:https://www.zhihu.com/question/20618891

原文地址:https://www.cnblogs.com/parent-absent-son/p/10133395.html