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

 

posted @   上海小墨子  阅读(530)  评论(1编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示