广告位联系
返回顶部
分享到

Java基础面试真题:String为什么是不可变的?

java 来源:互联网 作者:佚名 发布时间:2025-01-28 23:31:26 人浏览
摘要

+ 目录 今天来分享一道群友去阿里云面试遇到的 Java 基础面试真题:String、StringBuffer、StringBuilder的区别?String为什么是不可变的?。 网站很多文章都把String不可变的原因讲错了,建议你重点关

Java技术迷

+

目录

今天来分享一道群友去阿里云面试遇到的 Java 基础面试真题:“String、StringBuffer、StringBuilder 的区别?String 为什么是不可变的?”。

网站很多文章都把 String 不可变的原因讲错了,建议你重点关注一下。另外,本文还提到了 :“Java 9 为何要将 String 的底层实现由 char[] 改成了 byte[] ?”

下面是正文。

可变性

简单的来说:String 类中使用 final 关键字修饰字符数组来保存字符串,所以String 对象是不可变的。×

1

2

3

4

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

    private final char value[];

 //...

}

???? 修正 :我们知道被 final 关键字修饰的类不能被继承,修饰的方法不能被重写,修饰的变量是基本数据类型则值不能改变,修饰的变量是引用类型则不能再指向其他对象。因此,final 关键字修饰的数组保存字符串并不是 String 不可变的根本原因,因为这个数组保存的字符串是可变的(final 修饰引用类型变量的情况)。

String 真正不可变有下面几点原因:

保存字符串的数组被 final 修饰且为私有的,并且String 类没有提供/暴露修改这个字符串的方法。

String 类被 final 修饰导致其不能被继承,进而避免了子类破坏 String 不可变。

相关阅读:如何理解 String 类型值的不可变?- 知乎提问[1]

补充(来自issue 675[2]):在 Java 9 之后,String 、StringBuilder 与 StringBuffer 的实现改用 byte 数组存储字符串。

Java 9 为何要将 String 的底层实现由 char[] 改成了 byte[] ?

新版的 String 其实支持两个编码方案:Latin-1 和 UTF-16。如果字符串中包含的汉字没有超过 Latin-1 可表示范围内的字符,那就会使用 Latin-1 作为编码方案。Latin-1 编码方案下,byte 占一个字节(8 位),char 占用 2 个字节(16),byte 相较 char 节省一半的内存空间。

如果字符串中包含的汉字超过 Latin-1 可表示范围内的字符,byte 和 char 所占用的空间是一样的。

这是官方的介绍:https://openjdk.java.net/jeps/254 。

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

1

2

3

4

5

6

7

8

9

10

11

12

13

abstract class AbstractStringBuilder implements Appendable, CharSequence {

    char[] value;

    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;

    }

   //...

}

线程安全性

String 中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类,定义了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共方法。StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。

性能

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

对于三者使用的总结:

  • 操作少量的数据: 适用 String
  • 单线程操作字符串缓冲区下操作大量数据: 适用 StringBuilder
  • 多线程操作字符串缓冲区下操作大量数据: 适用 StringBuffer

版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 :
相关文章
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计