Java中StringStringBuilderStringBuffer常用源码分析及比较:StringBuilderStringBuffer源码分析
Posted Stphen糖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中StringStringBuilderStringBuffer常用源码分析及比较:StringBuilderStringBuffer源码分析相关的知识,希望对你有一定的参考价值。
StringBuilder:
一、构造方法:
/** * Constructs a string builder with no characters in it and an * initial capacity of 16 characters. */ public StringBuilder() { super(16); } /** * Constructs a string builder with no characters in it and an * initial capacity specified by the <code>capacity</code> argument. * * @param capacity the initial capacity. * @throws NegativeArraySizeException if the <code>capacity</code> * argument is less than <code>0</code>. */ public StringBuilder(int capacity) { super(capacity); } /** * Constructs a string builder initialized to the contents of the * specified string. The initial capacity of the string builder is * <code>16</code> plus the length of the string argument. * * @param str the initial contents of the buffer. * @throws NullPointerException if <code>str</code> is <code>null</code> */ public StringBuilder(String str) { super(str.length() + 16); append(str); } /** * Constructs a string builder that contains the same characters * as the specified <code>CharSequence</code>. The initial capacity of * the string builder is <code>16</code> plus the length of the * <code>CharSequence</code> argument. * * @param seq the sequence to copy. * @throws NullPointerException if <code>seq</code> is <code>null</code> */ public StringBuilder(CharSequence seq) { this(seq.length() + 16); append(seq); }
从代码可知,StringBuilder的不管哪个构造方法,都用到了父类AbstractStringBuilder的构造方法,那么来看一下它的父类AbstractStringBuilder。
成员变量+构造方法:
/** * The value is used for character storage. */ char[] value; /** * The count is the number of characters used. */ int count; /** * This no-arg constructor is necessary for serialization of subclasses. */ AbstractStringBuilder() { } /** * Creates an AbstractStringBuilder of the specified capacity. */ AbstractStringBuilder(int capacity) { value = new char[capacity]; }
从该父类就可以看出,StringBuilder与String一样是通过char数组value来存字符串,但不一样的是这个value数组没有用final修饰,这也是StringBuilder可以直接通过改变value做字符串拼接的原因。StringBuilder可以直接通过构造方法直接初始化value容量大小,值得注意的是,AbstractStringBuilder类拥有一个变量count,用来表示char数组中字符串真实长度,故以下两个方法,length方法返回的是该StringBuilder中字符串的真实长度,capacity方法返回的是value数组的容量。
/** * Returns the length (character count). * * @return the length of the sequence of characters currently * represented by this object */ public int length() { return count; } /** * Returns the current capacity. The capacity is the amount of storage * available for newly inserted characters, beyond which an allocation * will occur. * * @return the current capacity */ public int capacity() { return value.length; }
成员方法:
append方法:
public StringBuilder append(Object obj) { return append(String.valueOf(obj)); } public StringBuilder append(String str) { super.append(str); return this; } // Appends the specified string builder to this sequence. private StringBuilder append(StringBuilder sb) { if (sb == null) return append("null"); int len = sb.length(); int newcount = count + len; if (newcount > value.length) expandCapacity(newcount); sb.getChars(0, len, value, count); count = newcount; return this; } /** * Appends the specified <tt>StringBuffer</tt> to this sequence. * <p> * The characters of the <tt>StringBuffer</tt> argument are appended, * in order, to this sequence, increasing the * length of this sequence by the length of the argument. * If <tt>sb</tt> is <tt>null</tt>, then the four characters * <tt>"null"</tt> are appended to this sequence. * <p> * Let <i>n</i> be the length of this character sequence just prior to * execution of the <tt>append</tt> method. Then the character at index * <i>k</i> in the new character sequence is equal to the character at * index <i>k</i> in the old character sequence, if <i>k</i> is less than * <i>n</i>; otherwise, it is equal to the character at index <i>k-n</i> * in the argument <code>sb</code>. * * @param sb the <tt>StringBuffer</tt> to append. * @return a reference to this object. */ public StringBuilder append(StringBuffer sb) { super.append(sb); return this; } /** */ public StringBuilder append(CharSequence s) { if (s == null) s = "null"; if (s instanceof String) return this.append((String)s); if (s instanceof StringBuffer) return this.append((StringBuffer)s); if (s instanceof StringBuilder) return this.append((StringBuilder)s); return this.append(s, 0, s.length()); } /** * @throws IndexOutOfBoundsException {@inheritDoc} */ public StringBuilder append(CharSequence s, int start, int end) { super.append(s, start, end); return this; } public StringBuilder append(char[] str) { super.append(str); return this; } /** * @throws IndexOutOfBoundsException {@inheritDoc} */ public StringBuilder append(char[] str, int offset, int len) { super.append(str, offset, len); return this; } public StringBuilder append(boolean b) { super.append(b); return this; } public StringBuilder append(char c) { super.append(c); return this; } public StringBuilder append(int i) { super.append(i); return this; } public StringBuilder append(long lng) { super.append(lng); return this; } public StringBuilder append(float f) { super.append(f); return this; } public StringBuilder append(double d) { super.append(d); return this; }
可以看出StringBuilder的append方法还是来自它的父类AbstractStringBuilder,直接贴上父类append,只列出几个常用的
/** * Appends the string representation of the {@code Object} argument. * <p> * The overall effect is exactly as if the argument were converted * to a string by the method {@link String#valueOf(Object)}, * and the characters of that string were then * {@link #append(String) appended} to this character sequence. * * @param obj an {@code Object}. * @return a reference to this object. */ public AbstractStringBuilder append(Object obj) { return append(String.valueOf(obj)); } /** * Appends the specified string to this character sequence. * <p> * The characters of the {@code String} argument are appended, in * order, increasing the length of this sequence by the length of the * argument. If {@code str} is {@code null}, then the four * characters {@code "null"} are appended. * <p> * Let <i>n</i> be the length of this character sequence just prior to * execution of the {@code append} method. Then the character at * index <i>k</i> in the new character sequence is equal to the character * at index <i>k</i> in the old character sequence, if <i>k</i> is less * than <i>n</i>; otherwise, it is equal to the character at index * <i>k-n</i> in the argument {@code str}. * * @param str a string. * @return a reference to this object. */ public AbstractStringBuilder append(String str) { if (str == null) str = "null"; int len = str.length(); ensureCapacityInternal(count + len); str.getChars(0, len, value, count); count += len; return this; } // Documentation in subclasses because of synchro difference public AbstractStringBuilder append(StringBuffer sb) { if (sb == null) return append("null"); int len = sb.length(); ensureCapacityInternal(count + len); sb.getChars(0, len, value, count); count += len; return this; }
通过可以看出以上代码看出两点:1.append对传入的参数进行了判空,且为空是将字符串“null”拼接了进去,与String类型的‘+’拼接null字符串一样
2.如果values的容量大小不足以装下拼接后的字符串,会重建一个value,并将之前的value复制进去,具体反映在:
/** * This method has the same contract as ensureCapacity, but is * never synchronized. */ private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code if (minimumCapacity - value.length > 0) expandCapacity(minimumCapacity); } /** * This implements the expansion semantics of ensureCapacity with no * size check or synchronization. */ 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 static char[] copyOf(char[] original, int newLength) { char[] copy = new char[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
StringBuffer:
public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence
通过StringBuffer类的定义及构造方法,我们可以看到其实和StringBuilder非常类似甚至完全一样,不必多说,StringBuffer也是通过char数组value
来存字符串,且一样是没有final修饰。
append方法:
public synchronized StringBuffer append(Object obj) { super.append(String.valueOf(obj)); return this; } public synchronized StringBuffer append(String str) { super.append(str); return this; } /** * Appends the specified <tt>StringBuffer</tt> to this sequence. * <p> * The characters of the <tt>StringBuffer</tt> argument are appended, * in order, to the contents of this <tt>StringBuffer</tt>, increasing the * length of this <tt>StringBuffer</tt> by the length of the argument. * If <tt>sb</tt> is <tt>null</tt>, then the four characters * <tt>"null"</tt> are appended to this <tt>StringBuffer</tt>. * <p> * Let <i>n</i> be the length of the old character sequence, the one * contained in the <tt>StringBuffer</tt> just prior to execution of the * <tt>append</tt> method. Then the character at index <i>k</i> in * the new character sequence is equal to the character at index <i>k</i> * in the old character sequence, if <i>k</i> is less than <i>n</i>; * otherwise, it is equal to the character at index <i>k-n</i> in the * argument <code>sb</code>. * <p> * This method synchronizes on <code>this</code> (the destination) * object but does not synchronize on the source (<code>sb</code>). * * @param sb the <tt>StringBuffer</tt> to append. * @return a reference to this object. * @since 1.4 */ public synchronized StringBuffer append(StringBuffer sb) { super.append(sb); return this; }
可以看到与StringBuilder唯一不同的是每个append方法都加了synchronized修饰,即锁(不允许多线程同时访问),这也是StringBuffer是线程安全的,StringBuilder是线程不安全的原因
以上是关于Java中StringStringBuilderStringBuffer常用源码分析及比较:StringBuilderStringBuffer源码分析的主要内容,如果未能解决你的问题,请参考以下文章