为什么String 是不可变的?

前言

为什么在java中String是不可变的?
为什么String要是不可变的?意义何在?

问题一:为什么在java中String是不可变的?

初学者会遇到一些疑问,

“都说String不可变,可是我明明可以改一个String啊”

对,就像下面一样

public class test {
    public static void main(String[] args) {
        String oldStr = "阳光大男孩!!!";
        System.out.println(oldStr);
        oldStr = oldStr.substring(3);
        System.out.println(oldStr);
    }
}

输出结果是

阳光大男孩!!!
男孩!!!

你看,这不是能变吗?博主辣鸡!

这其实是对于String不可变性理解的一个误区

这段代码其实是这样一个过程

  1. 新申请一个字符串,内容为“阳光大男孩!!!”
  2. 输出字符串的值
  3. 对字符串执行截取操作,新建了一个字符串对象!!!,再让oldStr指向了这个新建的对象。
  4. 打印oldStr,这时候oldStr指向的是新对象,所以值是“男孩!!!”

佐证一下

我们打开substring方法的源码看看

public String substring(int beginIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        int subLen = value.length - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
    }

最后一行进行了一个三则表达式,如果beginIndex是0的话,说明根本不需要截取,所以直接返回原来的对象,否则,新建一个对象

所以,你表面上改变了字符串的值,其实没有,原来的字符串并没有改变,而是新new了一个对象。

问题二:为什么String要是不可变的?意义何在?

  • 字符串的实现是数组,数组是顺序存储的,所以在创建时就开辟了一个连续地址
  • 多线程有共享变量的需要,String的不可变性,让程序变的安全,因为不可变意味着不可写只能读,所以是安全的。
  • 字符串常量池的设计可以提高代码效率,节省空间,而String的不可变性正是一个前提条件。

关于字符串常量池浅析

public class test {
    public static void main(String[] args) {
        String oldStr1 = "阳光大男孩!!!";
        String oldStr2 = "阳光大男孩!!!";
        System.out.println(oldStr1.hashCode());
        System.out.println(oldStr2.hashCode());
    }
}

输出一下

1402535102
1402535102

可以看得出来这两个对象引用的都是同一个地址,

  • 在创建第一个对象的时候,创建完成后,同时会把它放到字符串常量池中。
  • new 第二个对象的时候,会去字符串常量池中比较,如果有,则让实例直接指向常量池中的地址,否则new一个新对象。
发布了200 篇原创文章 · 获赞 99 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/weixin_43889841/article/details/103413899