本文主要以简单的String/StringBuilder/StringBuffer操作来看这三个类的实现原理。
什么简单操作呢?那就是StringBuilder与StringBuffer的append() && toString()两个方法。
示例代码如下:
public class TestStringBuffer_Builder { public static void main(String[] args) { TestStringBuffer_Builder testStringBuffer_builder = new TestStringBuffer_Builder(); testStringBuffer_builder.testStringBuilder(); testStringBuffer_builder.testStringBuffer(); } public void testStringBuilder() { String strName = new String("JackMa"); String strCountry = new String("China"); StringBuilder stringBuilder = new StringBuilder(64); stringBuilder.append("Name:").append(strName).append("\n"); stringBuilder.append("Country:").append(strCountry).append("\n"); System.out.print(stringBuilder.toString()); } private void testStringBuffer() { String strName = new String("JackMa"); String strCountry = new String("China"); StringBuffer stringBuffer = new StringBuffer(64); stringBuffer.append("Name:").append(strName).append("\n"); stringBuffer.append("Country:").append(strCountry).append("\n"); System.out.print(stringBuffer.toString()); } }
以上的demo中,涉及到了String的构造,StringBuilder & StringBuffer的构造、append与toString。我们分别研究这几个方法,来了解其内部的实现原理。
一、String
代码中首先构造了String。
先简单看看String内部发生了什么:
public final class String { private final char value[]; private int hash; public String() { this.value = "".value; } public String(String original) { this.value = original.value; this.hash = original.hash; } public String(char value[]) { this.value = Arrays.copyOf(value, value.length); } public String concat(String str) { int otherLen = str.length(); if (otherLen == 0) { return this; } int len = value.length; char buf[] = Arrays.copyOf(value, len + otherLen); str.getChars(buf, len); return new String(buf, true); } }
可以看的出来,String中的数据都是保存在数组char value[]中。
对于String的concat(拼接)过程可以看出,最后生成了一个新的String对象作为拼接的结果。
二、StringBuilder
先看看StringBuilder中的方法:
public class StringBuilder extends AbstractStringBuilder { public StringBuilder(int capacity) { super(capacity); } public StringBuilder append(String str) { super.append(str); return this; } } 父类: public abstract class AbstractStringBuilder { char[] value; AbstractStringBuilder(int capacity) { value = new char[capacity]; } 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; } private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code if (minimumCapacity - value.length > 0) expandCapacity(minimumCapacity); } void expandCapacity(int minimumCapacity) { int newCapacity = value.length * 2 + 2; if (newCapacity - minimumCapacity < 0) newCapacity = minimumCapacity; if (newCapacity < 0) { if (minimumCapacity < 0) // overflow throw new OutOfMemoryError(); newCapacity = Integer.MAX_VALUE; } value = Arrays.copyOf(value, newCapacity); } public String toString() { // Create a copy, don‘t share the array return new String(value, 0, count); } }
StringBuilder中也是用数组进行数据保存。相比于String的concat操作,StringBuilder在拼接字符串的过程始终是一个对象在操作,变化的是StringBuilder内部的数组若容量不够,则进行扩充。
扩容算法中,在拼接字符串不长的情况下,容量通常扩为2倍。若2倍不足,则扩为需要的大小。
在toString方法中,使用StringBuilder内部的value数组构造一个新的的String对象,并返回。
三、StringBuffer
public final class StringBuffer extends AbstractStringBuilder { private transient char[] toStringCache; public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); return this; } public synchronized String toString() { if (toStringCache == null) { toStringCache = Arrays.copyOfRange(value, 0, count); } return new String(toStringCache, true); } }
StringBuffer中,也是用数组进行字符串数据保存。不同于StringBuilder,StringBuffer中的操作字符串方法是同步的,因此属于线程安全类。
同时用了transient char[] toStringCache来缓存数据。在调用toString时,将字符串内容保存进toStringCache, 且在修改StringBuffer时(例如append、insert、delete等字符操作),清空该缓存。
若字符串无修改,在第二次调用toString时直接将缓存内容返回,从而提升字符转换效率。
这里面涉及到一个点:用于缓存字符内容的数组toStringCache是用transient修饰,直接访问内存,从而实现线程间的可见性。具体内容可进一步了解关键字transient。
原文地址:https://www.cnblogs.com/xinxinBlog/p/10176838.html