String 为什么是不可变的

什么是不可变

String 对象的不可变指的是,任何对于 String 对象的操作不是在原内存地址上修改数据,而是重新指向一个新对象,新地址。

在这里插入图片描述

为什么是不可变的

Java 关于 String 的源码如下:

public final class String

    implements java.io.Serializable, Comparable<String>, CharSequence {

    /** The value is used for character storage. */

    private final char value[];

}    

final 关键字修饰的类不能被继承,修饰的方法不能被重写,修饰的变量是基本类型则初始化后不能被改变,修饰的变量是引用类型初始化后不能再指向其它的对象。

String 类是用关键字 final 修饰的,使得 String 类不可被继承,进而避免了破坏 String 类的不可变。

成员变量 value 是用 final 修饰的,保证了 value 的引用地址不可变,但是里面的具体元素是可以被改变的。看下面这个例子:

final int[] value = {1,2};

int[] another = {4,5,6};

value = another; // 编译报错,final 不可变

编译器不允许我们直接讲 value 指向堆区的另一个地址,但是如果我们直接对数组元素动手,是可以修改 value 里的元素值的。

final int[] value = {1,2};

value[1] = 3;

所以,String 不可变的真正原因是:

  1. 保存字符串的数组被 final 修饰且为私有的,并且String 类没有提供/暴露修改这个字符串的方法。
  2. String 类被 final 修饰导致其不能被继承,进而避免了子类破坏 String 不可变。

不可变的好处与坏处

线程安全性(好处)

在并发场景下,多个线程读取同一个资源,是不会引发竟态条件的。只有在对资源进行些操作时才有危险。不可变对象不能被修改,所以是线程安全的。

节省空间,提高效率(好处)

在这里插入图片描述

String 还有字符串常量池的属性, one 和 two 两个变量指向的是同一个地址。在大量使用字符串的情况下,可以节省内存空间,提高效率。
String 的不可变条件是必要条件,要是内存啦字符串内容能够改来改去,这么做就完全没有意义。

修改性能不高(坏处)

由于 String 的不可变性,每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。
为什么引入 StringBuilder,StringBuffer

StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是使用字符数组保存字符串,不过没有使用 final 和 private 关键字修饰,最关键的是这个 AbstractStringBuilder 类还提供了很多修改字符串的操作,如 expandCapacity、append、insert、indexOf 等公共方法。

abstract class AbstractStringBuilder implements Appendable, CharSequence {

    char[] value;

    // append 方法

    public AbstractStringBuilder append(String str) {

        if (str == null)

            return appendNull();

        int len = str.length();

        ensureCapacityInternal(count + len);

        str.getChars(0, len, value, count);

        count += len;

        return this;

    }

   //...

}

StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。

StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用 StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。

参考资料

阿里云二面: String 为什么不可变?

如何理解 String 类型值的不可变?

你知道StringBuffer是如何扩容的吗?

  • 14
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值