StringStringBuffer和StringBuilder源码解析

Posted 一响贪欢

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了StringStringBuffer和StringBuilder源码解析相关的知识,希望对你有一定的参考价值。

1.String

1.1类的定义

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

String类在定义时候使用final关键字进行修饰,限制了这个类无法被继承,里面的方法也无法被重写。

同时它还实现了Serializable接口、Comparable接口,以及CharSequence接口三个接口:

  • Serializable:序列化接口,如果允许对象被序列化需要实现该类。
  • Comparable:比较对象大小的接口,用来定义对象之间如何进行大小的比较。
  • CharSequence:字符序列接口,相比String类,它是一个更为广泛的可读可写字符序列,而String类是只可读的。

1.2类的成员变

    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0

String类中常用的两个成员变量value、hash。

  • value:字符类型的数组,用来存放我们所保存的字符串,每一个字符串都会被拆开作为字符来进行存储
  • hash:对应字符串的hash值。

1.3常用方法

length():返回value数组的长度。

    public int length() {
        return value.length;
    }

 

indexOf(str):获取在字符串中某个字符串的起始位置。这里其实也是用的遍历,从指定的开始位置起,一直遍历直到找到目标字符串,或者直到源字符串的最后一位(其实是最后一位减去目标字符串的长度)。

    public int indexOf(String str) {
        return indexOf(str, 0);
    }

    public int indexOf(String str, int fromIndex) {
        return indexOf(value, 0, value.length,
                str.value, 0, str.value.length, fromIndex);
    }

    static int indexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount,
            int fromIndex) {
        if (fromIndex >= sourceCount) {
            return (targetCount == 0 ? sourceCount : -1);
        }
        if (fromIndex < 0) {
            fromIndex = 0;
        }
        if (targetCount == 0) {
            return fromIndex;
        }

        char first = target[targetOffset];
        int max = sourceOffset + (sourceCount - targetCount);

        for (int i = sourceOffset + fromIndex; i <= max; i++) {
            /* Look for first character. */
            if (source[i] != first) {
                while (++i <= max && source[i] != first);
            }

            /* Found first character, now look at the rest of v2 */
            if (i <= max) {
                int j = i + 1;
                int end = j + targetCount - 1;
                for (int k = targetOffset + 1; j < end && source[j]
                        == target[k]; j++, k++);

                if (j == end) {
                    /* Found whole string. */
                    return i - sourceOffset;
                }
            }
        }
        return -1;
    }

 

compareTo(str):比较两个字符串的大小,采用的是逐个字符来进行比较(比较ASCII码)。

    public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

 

1.4总结

String类是一个可序列化,可按照字符大小进行排序,不可继承、只读的字符序列类。

 

2.StringBuilder

2.1类定义

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence

StringBuilder和String的定义类似,同样被final关键字修饰,限定了无法被继承,同时继承Serializable和CharSequence两个接口。

同时最它多继承了一个抽象类AblstractStringBuilder。

2.2成员变量

在StringBuilder中没有再定义其他的成员变量,所使用的底层存放数据的变量来自于父类AbstractStringBuilder。

在AbstractStringBuilder中,定义了三个成员变量

    char[] value;

    int count;

    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
  • value:字符数组,用来存放传入的字符串。
  • count:int类型,记录value中存放元素的长度。
  • MAX_ARRAY_SIZE:静态常量,代指允许value数组的最大长度。

2.3常用方法

append(str):相比String只读的属性,StringBuilder允许我们对其进行写操作。但是由于底层存放数据的是一个数组,因此每次都需要进行一个扩容的判断。如果count+入参字符串的长度大于当前数组value的长度,就需要进行扩容,每次扩容后的数组长度=原长度*2+2。

    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) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));
        }
    }

    private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int newCapacity = (value.length << 1) + 2;
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;
        }
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
            ? hugeCapacity(minCapacity)
            : newCapacity;
    }

2.4总结

StringBuilder补充了String只能读不能写的属性,采用对数组扩容的操作,允许程序员对String类型来进行写操作。

 

3.StringBuffer

3.1类定义

 public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence

StringBuffer的定义与StringBuilder类似,同样继承了AbstractStringBuilder抽象类,实现了Serializable和CharSequence接口。

3.2成员变量

StringBuffer的成员变量和StringBuilder一样,同样适用在AbstractStringBuilder中定义好的字符类型数组value和int类型count。

3.3常用方法

append(str):与StringBuilder类似的,两个类都是通过调用AbstractStringBuilder中的append(str)方法来添加字符串。

区别在于StringBuffer的方法定义上多了一个关键字:Synchronized。通过这个关键字,来保证我们对字符串的写操作的线程安全。

    @Override
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }

toString():和StringBuilder的toString()方法不一样,这里在StringBuffer中就已经完成了对字符数组的复制,如果连续调用toString()方法,实际返回的都是同一个String对象。而在StringBuilder中,由于数组的复制是发生在String类里面,因此每次调用后返回的都是不同的String对象。

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

 

3.4总结

StringBuffer在Stringbuilder实现了字符串写操作的基础上,又添加了对它的线程安全方面的维护,通过查看源码,可见都是通过在方法上添加synchronized关键字来显示的。这样虽然可以保证线程安全,但是也在一定程度上,舍弃了部分性能。不过在jdk1.5之后对锁的优化,新增了偏向锁、轻量级锁后,如果我们对字符串的写操作不涉及多线程的时候,StringBuffer和StringBuilder的资源损耗是几乎类似的。但如果一旦涉及多线程,StringBuffer则能更好的保障我们的线程安全。

 

4.总结

String类是java中定义用来保存一个字符序列的对象,但是对它的操作只有读,而没有写。所有的写操作实际都是返回了一个新的字符串对象。

StringBuilder类在String类的基础上,增加了对字符序列的写操作,采用底层数组扩容的方式,来允许添加新的字符串,或删除里面原有的字符串。

StringBuffer类由在StringBuilder类的基础上,既满足了对字符序列的写操作,又保证了操作的线程安全。因此在实际情况下,优先推荐使用StringBuffer类。

 

 

成员变量

String类型

以上是关于StringStringBuffer和StringBuilder源码解析的主要内容,如果未能解决你的问题,请参考以下文章

StringStringBuffer和StringBuild

StringStringBuffer和StringBuild

StringStringBuffer和StringBuild

StringStringBuffer和StringBuilder比较

StringStringBuffer和StringBuilder区别及性能分析

stringstringbuffer和stringbuilder的区别