对String,StringBuilder,StringBuffer的理解

 平时我们一般涉及到字符串的拼接,最本能最直接的方法就是+.

String s1 = "Hello";
s1=s1+"word";

当数据拼接次数比较少的时候,这样的方法无可厚非,但是一旦次数较多时,这样的方法效率很低,而且浪费大量的空间

现在我要讲的是String,StringBuilder,StringBuffer,这三个有什么区别,以及平时我们使用时该注意什么?

1.String

      String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且大量浪费有限的内存空间。

      为什么会浪费大量的空间?

             看上面的代码,假设s1指向地址0x0001 ,当重新赋值后s1指向的地址是0x0002了,然而地址0x0001里保存的s1依然存在,这就导致了每次重新赋值,就会产生一个新的地址指向(新的对象),而原来的不会消失,浪费了大量的空间,因此String的操作都是改变赋值地址而不是改变值操作,最后,原来的对象就会变为垃圾被GC回收掉,可想而知这样执行效率会有多底。

             除此之外字符串拼接还有str.concat("test");方法,这个重新赋值也会产生新的对象,但效率会比+高一点。

2.StringBuffer

      StringBuffer是可变类和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。 每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量。

    /**
     * Constructs a string builder with no characters in it and an
     * initial capacity of 16 characters.
     */
     public StringBuilder() {
        super(16);
     }


    /**
     * Constructs a string builder initialized to the contents of the
     * specified string. The initial capacity of the string builder is
     * {@code 16} plus the length of the string argument.
     *
     * @param   str   the initial contents of the buffer.
     */
    public StringBuilder(String str) {
        super(str.length() + 16);
        append(str);
    }

       看上面的源码我们会发现

        StringBuffer buf=new StringBuffer(); //分配长16字节的字符缓冲区 
        StringBuffer buf=new StringBuffer("this"); //分配长"this".length()+16字节的字符缓冲区 
        StringBuffer buf=new StringBuffer("this")//在缓冲区中存放了字符串,并在后面预留了16字节的空缓冲区。 

       那么字符串大小超过容量时是怎么扩容的呢?

         这可能就涉及到其常用的append方法了

    public StringBuilder append(StringBuffer sb) {
        super.append(sb);
        return this;
    }

    // Documentation in subclasses because of synchro difference
    public AbstractStringBuilder append(StringBuffer sb) {
        if (sb == null)
            return appendNull();
        int len = sb.length();
        ensureCapacityInternal(count + len);
        sb.getChars(0, len, value, count);
        count += len;
        return this;
    }

     /**
     * For positive values of {@code minimumCapacity}, this method
     * behaves like {@code ensureCapacity}, however it is never
     * synchronized.
     * If {@code minimumCapacity} is non positive due to numeric
     * overflow, this method throws {@code OutOfMemoryError}.
     */
    private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));
        }
    }

     /**
     * Returns a capacity at least as large as the given minimum capacity.
     * Returns the current capacity increased by the same amount + 2 if
     * that suffices.
     * Will not return a capacity greater than {@code MAX_ARRAY_SIZE}
     * unless the given minimum capacity is greater than that.
     *
     * @param  minCapacity the desired minimum capacity
     * @throws OutOfMemoryError if minCapacity is less than zero or
     *         greater than Integer.MAX_VALUE
     */
    private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int newCapacity = (value.length << 1) + 2;(value.length << 1表示原来的2倍,这个是二进制写法后的转换问题)
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;
        }
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
            ? hugeCapacity(minCapacity)
            : newCapacity;
    }

    private int hugeCapacity(int minCapacity) {
        if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
            throw new OutOfMemoryError();
        }
        return (minCapacity > MAX_ARRAY_SIZE)
            ? minCapacity : MAX_ARRAY_SIZE;
    }

    看上面的源码会发现扩容到原来的两倍+2的长度,如果还是不够的话就用到了minimumCapacity=count+len这个长度

3.StringBuilder

       StringBuilder 类在 Java 5中被提出来的,相对于上面的StringBuffer,但这个不是线程安全的(不能同步访问),由于它不执行同步,StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。

 

你可能感兴趣的:(java基础)