• Java中String、StringBuilder、StringBuffer常用源码分析及比较(二):StringBuilder、StringBuffer源码分析


    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是线程不安全的原因

  • 相关阅读:
    laravel 控制器方法里存get值 和 blade 模板获得闪存值的方法
    获取对象中的值的方法
    python3 语法小结
    集合一些方法陷阱
    文件的读写操作
    字符编码
    数字,字符串,列表,元祖,字典,集合类型内置方法
    if判断,while循环,for循环
    交互,格式化输出,运算符,解压缩!
    python基础知识
  • 原文地址:https://www.cnblogs.com/tz346125264/p/7624907.html
Copyright © 2020-2023  润新知