关于 String、StringBuffer、StringBuilder 的常见面试题

String

类不可变(final),内部维护的 char[] value 数组不可变(final)。

创建

方式一

String str = "abc";

字符串常量池如果有 “abc”,不创建对象;如果没有,在字符串常量池创建"abc"。
在这里插入图片描述

注意:字符串常量池逻辑上属于方法区,物理上存在于堆中

方式二

String str = new String("abc");

字符串常量池如果有 “abc”,创建一个对象在堆;如果没有,在字符串常量池创建"abc",在堆中创建一个对象。

public String(String original) {
    this.value = original.value;
    this.hash = original.hash;
}

源码中,直接共用了一个数组,因为反正 String 都是不可变的。就算你,更改了一个 String,也只是将它指向了另一个对象。
在这里插入图片描述

方法三

String a = new String("abc").intern();
String b = new String("abc").intern();

通过前文可以知道,最终会有3个对象,字符串常量池1个,堆2个。
但调用 intern(),返回的是字符串常量池的引用,所以 a==b。

方式四

动态创建:拼接,通过动态创建 char[] 数组等

最大长度

方式一和方式二:String 长度最大 65534,受字符串常量池(65535)和编译器(65534)限制。
方式三:受 String 的 成员变量 value 的限制,它是一个数组,数组的最大长度受 Integer.MAX_VALUE (231-1)限制,所以 String 理论上的最大长度也是 231-1。但实际上,String 的最大长度会相对少一点,Integer.MAX_VALUE - 2 或 2 ^ 31 - 3,不同电脑上可能有差异。

拼接

方式一

String str = "a" + 123 + "b" ;

编译器优化,直接创建 “a123b”

方式二

String str = "a";
str =  str  + "b" ;
  1. 创建 “a”
  2. 创建 StringBuilder
  3. append(“a”)
  4. 创建 “b”
  5. append(“b”)
  6. toString()

类似于第二行的操作,一行新建一个 StringBuilder;如果实在循环里,一次循环新建一次 StringBuilder

StringBuilder

内部维护 char[] value, 默认初始化数组容量为16。

append

  1. 如果容量不够,创建新数组
  2. System.arraycopy,复制旧数据到新数组,令新数组为 value
  3. 给 value 赋新数据

toString

  1. 新建 String 对象
  2. 赋 value 为 StringBuilder 的 value 的拷贝

StringBuffer

内部维护 char[] value, 默认初始化数组容量为16。
内部维护 char[] toStringCache,用于 toString 方法,每次修改 StringBuffer 都会,清空 toStringCache。

与 StringBuilder 拥有共同的父类
在这里插入图片描述
与 StringBuilder 相比,大部分方法都采用了 Synchronized 关键字修饰,以此来实现在多线程下的操作字符串的安全性。

toString

@Override
public synchronized String toString() {
    if (toStringCache == null) {
        toStringCache = Arrays.copyOfRange(value, 0, count);
    }
    return new String(toStringCache, true);
}

toStringCache 只有在这里才被赋值,也就是说只有调用 toString(),toStringCache 才有值。
使用场景极为有限。


额外说明一点:无论是 String 的 + 拼接,还是 StringBuffer 和 StringBuilder 的 append,都能拼接 null。

public class Test {
    public static void main(String[] args) {
        String a = null + "a"  + 1;
        System.out.println(a);
        String b = null;
        StringBuilder sb = new StringBuilder();
        sb.append(b);//sb.append(null);会编译不通过
        System.out.println(sb.toString());
    }
}

结果
在这里插入图片描述

©️2020 CSDN 皮肤主题: 岁月 设计师: pinMode 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值