【Java】手撕面试官之String、StringBuffer 和StringBuilder 的区别

一.定义

先从类定义来看看:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
......
}
public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
......
}
 public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
......
}
  • 都是用final修饰,不可被继承,即没有子类,可以防止子类覆盖情况的发生。
  • String 实现了Comparable<String>
  • StringBuffer 和 StringBuilder 都继承了AbstractStringBuilder类。
  • 三者均实现了java.io.Serializable, CharSequence接口。

二、无参数构造函数

1. 首先,看一下String的无参构造函数源代码:

public String() {
    this.value = new char[0];
}
  • 该函数创建了一个空字符序列(character  sequence)对象。由于字符串是不可变的,所以该构造函数没有必要用。
private final char value[];
  • this.value = new char[0],初始化一个空char数组value
  • value是一个字符数组

2.  然后我们看看StringBuilder()源代码:

public StringBuilder() {
    super(16);
}

super(16)是父类 AbstractStringBuilder的构造函数:

AbstractStringBuilder(int capacity) {
    value = new char[capacity];
}

同String一样,value是一个字符数组:

char[] value;

StringBuilder()方法创建了一个大小16的字符数组 ,用于存储字符。

3. 继续看 StringBuffer():

public StringBuffer() {
    super(16);
}

StringBuffer的父类也是AbstractStringBuilder,所以同StringBuilder()一样,创建了一个大小16的字符数组

由以上可以知道:

String()创建一个字符数组;

而StringBuffer()和StringBuffer()创建一个大小为16的字符数组。

String的字符数组value是final的,而StringBuffer和StringBuffer则不是。

 

三、带有初始字符串的构造函数

开发中常用的,创建一个指定字符串内容的对象,代码如下: 

String s = new String("qqq");

StringBuilder sb = new StringBuilder("qqq");

StringBuffer  sb1 = new StringBuffer("qqq");

1. 首先看看new String("qqq")的源代码

public String(String original) {

    this.value = original.value;

    this.hash = original.hash;

}

实际上,就是把参数original字符串对象的字符数组value和hash code直接赋值给新对象。我们已经知道value是字符数组,那么hash是什么呢,先看定义:

private int hash; // Default to 0

hash是字符串的哈希code,默认值是0。那么哈希code计算将在后续说明。

2. 再看看new StringBuilder("qqq")源代码:

public StringBuilder(String str) {

    super(str.length() + 16);

    append(str);

}

此处,

  • 第一步,初始化数组。super(str.length() + 16)AbstractStringBuilder构造函数:
AbstractStringBuilder(int capacity) {

    value = new char[capacity];

}

可以看出,这里创建的字符数组容量=参数str大小的+16

  • 第二步,赋值。append(str)定义如下
@Override

public StringBuilder append(String str) {

    super.append(str);

    return this;

}

赋值时候,调用了父类方法super.append(str)

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;

}

如果str参数是null,则赋值“null”;

如果str参数非null,判断是否有足够的空间容纳str字符串,如不够则扩容,需要最小空间是:已用字符数(count)+str的字符数。

使用str.getChars方法将字符串中的字符复制到字符数组value中。

更新已用字符数count

3. 最后看看new StringBuffer ("qqq")源代码

public StringBuffer(String str) {

    super(str.length() + 16);

    append(str);

}

StringBuffer构造方法与StringBuilder一样,需要注意的是append方法是加了同步锁synchronized

@Override

public synchronized StringBuffer append(String str) {

    toStringCache = null;

    super.append(str);

    return this;

}

 

四、字符数组value的区别

String使用字符数组value存储字符串数据。其定义的value是有final修饰的,代表该变量不可变的,所以String对象也就是不可变的。定义代码如下:

private final char value[];

StringBufferStringBuilder使用字符数组value存储字符串数据。value来自父类AbstractStringBuilderValue变量是可变的。定义代码如下:

char[] value;

 

五、线程安全的区别

  • String,由于value是final的。一旦创建就不会再被改变了,由于存储的字符串不会被改变。所以一定程度上能使String对象强制变得线程安全了。
  • StringBuffer,对调用方法加了同步锁synchronized,所以线程安全的。其中部分方法定义如下:
public synchronized StringBuffer append(StringBuffer sb) {

    toStringCache = null;

    super.append(sb);

    return this;

}

@Override

synchronized StringBuffer append(AbstractStringBuilder asb) {

    toStringCache = null;

    super.append(asb);

    return this;

}
  • StringBuilder则没有加同步锁,所以是非线程安全的。
@Override

public StringBuilder append(Object obj) {

    return append(String.valueOf(obj));

}

@Override

public StringBuilder append(String str) {

    super.append(str);

    return this;

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值