浅谈Java中的String、StringBuffer、StringBuilder

看再多别人的博客都不如自己翻一下源码:

String 内部使用final 修饰的byte[] 数组保存字符串,所以说String是不可变的。

@Stable
private final byte[] value;

为什么说String相加每次都会返回新的String对象?看下源码就知道了

字符串相加的时候先调用concat方法,最终是调用System.arraycopy这个方法把两个byte[]数组相加,在new 一个新的String对象返回,所以说每次字符串相加都会返回新的String对象。我们特别注意一下这个getBytes方法和System.arraycopy这两个方法,接下来查看StringBuffer和StringBuilder对象的时候还会说到。

1 void getBytes(byte dst[], int dstBegin, byte coder) {
2         if (coder() == coder) {
3             System.arraycopy(value, 0, dst, dstBegin << coder, value.length);
4         } else {    // this.coder == LATIN && coder == UTF16
5             StringLatin1.inflate(value, 0, dst, dstBegin, value.length);
6         }
7     }
 1 public String concat(String str) {
 2         int olen = str.length();
 3         if (olen == 0) {
 4             return this;
 5         }
 6         if (coder() == str.coder()) {
 7             byte[] val = this.value;
 8             byte[] oval = str.value;
 9             int len = val.length + oval.length;
10             byte[] buf = Arrays.copyOf(val, len);
11             System.arraycopy(oval, 0, buf, val.length, oval.length);
12             return new String(buf, coder);
13         }
14         int len = length();
15         byte[] buf = StringUTF16.newBytesFor(len + olen);
16         getBytes(buf, 0, UTF16);
17         str.getBytes(buf, len, UTF16);
18         return new String(buf, UTF16);
19     }

StringBuffer:继承之AbstractStringBuilder这个抽象类,这个抽象类内部使用 byte[] value;保存字符串的值,我们注意下和String的区别,String内部的byte[]数组使用了final关键字修饰。

我们再看看下append这个方法,注意看下7行、16行、21行的代码 ,是不是和String 字符相加的方法很像?确实是的,也是通过System.arraycopy这个方法完成字符串的拼接,只不过append这个方法内部调用了ensureCapacityInternal这个方法完成了byte[]数组长度的判断和数组的扩容。

 1 public AbstractStringBuilder append(String str) {
 2         if (str == null) {
 3             return appendNull();
 4         }
 5         int len = str.length();
 6         ensureCapacityInternal(count + len);
 7         putStringAt(count, str);
 8         count += len;
 9         return this;
10     }
11 
12  private final void putStringAt(int index, String str) {
13         if (getCoder() != str.coder()) {
14             inflate();
15         }
16         str.getBytes(value, index, coder);
17     }
18 
19 void getBytes(byte dst[], int dstBegin, byte coder) {
20         if (coder() == coder) {
21             System.arraycopy(value, 0, dst, dstBegin << coder, value.length);
22         } else {    // this.coder == LATIN && coder == UTF16
23             StringLatin1.inflate(value, 0, dst, dstBegin, value.length);
24         }
25     }
private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        int oldCapacity = value.length >> coder;
        if (minimumCapacity - oldCapacity > 0) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity) << coder);
        }
    }

StringBuilder 和StringBuffer都是继承之AbstractStringBuilder这个抽象类他们区别就在以自身的方法,看下面的代码

StringBuffer调用父类方法的时候使用了synchronized这个关键字来修饰,StringBuilder 直接调用父类的方法。如果我们仔细查看源代码就会发现StringBuffer的方法都使用了
synchronized这个关键字来修饰,所以StringBuffer是线程安全的,StringBuilder是线程不安全的。
StringBuffer比StringBuffer效率较低的原因也是因为synchronized保证了线程安全。数据完整性和效率之间本身就有矛盾,不能两者兼得。
 1 StringBuffer 的append方法
 2    @Override
 3     @HotSpotIntrinsicCandidate
 4     public synchronized StringBuffer append(String str) {
 5         toStringCache = null;
 6         super.append(str);
 7         return this;
 8     }
 9 
10 StringBuffer 的append方法
11 @Override
12     @HotSpotIntrinsicCandidate
13     public StringBuilder append(String str) {
14         super.append(str);
15         return this;
16     }

猜你喜欢

转载自www.cnblogs.com/liuyu7177/p/10499533.html
今日推荐