String、StringBuilder、StringBuffer之间的区别

String中的++符号操作的原理

/**
 * @author lizhangyu
 * @date 2020/6/13 1:30
 */
public class StringOperator {

    public static void main(String[] args) {

        StringBuffer sbf = new StringBuffer();

        String a = "a";
        String b = "b";

        String c = "23";
        String d = "2";
        String e = d + "3";
        String ab = a+b;
        StringBuilder sb = new StringBuilder();
        sb.append(1);
        System.out.println(c);
        System.out.println(e);
        System.out.println(c == e);
    }
}

  • 输出的结果为:
23
23
false
  • 字节码如下:
Compiled from "StringOperator.java"
public class test1.StringOperator {
  public test1.StringOperator();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class java/lang/StringBuffer
       3: dup
       4: invokespecial #3                  // Method java/lang/StringBuffer."<init>":()V
       7: astore_1
       8: ldc           #4                  // String a
      10: astore_2
      11: ldc           #5                  // String b
      13: astore_3
      14: ldc           #6                  // String 23
      16: astore        4
      18: ldc           #7                  // String 2
      20: astore        5
      22: new           #8                  // class java/lang/StringBuilder
      25: dup
      26: invokespecial #9                  // Method java/lang/StringBuilder."<init>":()V
      29: aload         5
      31: invokevirtual #10                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      34: ldc           #11                 // String 3
      36: invokevirtual #10                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      39: invokevirtual #12                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      42: astore        6
      44: new           #8                  // class java/lang/StringBuilder
      47: dup
      48: invokespecial #9                  // Method java/lang/StringBuilder."<init>":()V
      51: aload_2
      52: invokevirtual #10                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      55: aload_3
      56: invokevirtual #10                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      59: invokevirtual #12                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      62: astore        7
      64: new           #8                  // class java/lang/StringBuilder
      67: dup
      68: invokespecial #9                  // Method java/lang/StringBuilder."<init>":()V
      71: astore        8
      73: aload         8
      75: iconst_1
      76: invokevirtual #13                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      79: pop
      80: getstatic     #14                 // Field java/lang/System.out:Ljava/io/PrintStream;
      83: aload         4
      85: invokevirtual #15                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      88: getstatic     #14                 // Field java/lang/System.out:Ljava/io/PrintStream;
      91: aload         6
      93: invokevirtual #15                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      96: getstatic     #14                 // Field java/lang/System.out:Ljava/io/PrintStream;
      99: aload         4
     101: aload         6
     103: if_acmpne     110
     106: iconst_1
     107: goto          111
     110: iconst_0
     111: invokevirtual #16                 // Method java/io/PrintStream.println:(Z)V
     114: return
}
  • 可以看到String++符号操作底层用的是StringBuilder类中的append方法,最后再通过toString()方法进行实现的。
StringBuilder中的append()方法
  • 可以看到方法中调用的是super中的append方法
  @Override
    public StringBuilder append(int i) {
        super.append(i);
        return this;
    }
    /**
     * Appends the string representation of the {@code int}
     * argument to this sequence.
     * <p>
     * The overall effect is exactly as if the argument were converted
     * to a string by the method {@link String#valueOf(int)},
     * and the characters of that string were then
     * {@link #append(String) appended} to this character sequence.
     *
     * @param   i   an {@code int}.
     * @return  a reference to this object.
     */
    public AbstractStringBuilder append(int i) {
        if (i == Integer.MIN_VALUE) {
            append("-2147483648");
            return this;
        }
        int appendedLength = (i < 0) ? Integer.stringSize(-i) + 1
                                     : Integer.stringSize(i);
        int spaceNeeded = count + appendedLength;
        ensureCapacityInternal(spaceNeeded);
        Integer.getChars(i, spaceNeeded, value);
        count = spaceNeeded;
        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));
        }
    }
  • 复制方法如下:
    /**
     * Copies the specified array, truncating or padding with null characters (if necessary)
     * so the copy has the specified length.  For all indices that are valid
     * in both the original array and the copy, the two arrays will contain
     * identical values.  For any indices that are valid in the copy but not
     * the original, the copy will contain <tt>'\\u000'</tt>.  Such indices
     * will exist if and only if the specified length is greater than that of
     * the original array.
     *
     * @param original the array to be copied
     * @param newLength the length of the copy to be returned
     * @return a copy of the original array, truncated or padded with null characters
     *     to obtain the specified length
     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
     * @throws NullPointerException if <tt>original</tt> is null
     * @since 1.6
     */
    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;
    }

可以看到调用的是 System方法,方法如下:

public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);

调用的是native的本地方法

  • getChars()方法如下:
 /**
     * Places characters representing the integer i into the
     * character array buf. The characters are placed into
     * the buffer backwards starting with the least significant
     * digit at the specified index (exclusive), and working
     * backwards from there.
     *
     * Will fail if i == Integer.MIN_VALUE
     */
    static void getChars(int i, int index, char[] buf) {
        int q, r;
        int charPos = index;
        char sign = 0;

        if (i < 0) {
            sign = '-';
            i = -i;
        }

        // Generate two digits per iteration
        while (i >= 65536) {
            q = i / 100;
        // really: r = i - (q * 100);
            r = i - ((q << 6) + (q << 5) + (q << 2));
            i = q;
            buf [--charPos] = DigitOnes[r];
            buf [--charPos] = DigitTens[r];
        }

        // Fall thru to fast mode for smaller numbers
        // assert(i <= 65536, i);
        for (;;) {
            q = (i * 52429) >>> (16+3);
            r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ...
            buf [--charPos] = digits [r];
            i = q;
            if (i == 0) break;
        }
        if (sign != 0) {
            buf [--charPos] = sign;
        }
    }
StringBuffer和StringBuilder之间的区别

StringBuffer是线程安全的,因为StringBuffer方法加锁了,而StringBuilder方法没有加锁
StringBuffer对应的方法如下:

    @Override
    public synchronized int length() {
        return count;
    }

    @Override
    public synchronized int capacity() {
        return value.length;
    }


    @Override
    public synchronized void ensureCapacity(int minimumCapacity) {
        super.ensureCapacity(minimumCapacity);
    }

    /**
     * @since      1.5
     */
    @Override
    public synchronized void trimToSize() {
        super.trimToSize();
    }

    /**
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @see        #length()
     */
    @Override
    public synchronized void setLength(int newLength) {
        toStringCache = null;
        super.setLength(newLength);
    }

    /**
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @see        #length()
     */
    @Override
    public synchronized char charAt(int index) {
        if ((index < 0) || (index >= count))
            throw new StringIndexOutOfBoundsException(index);
        return value[index];
    }

StringBuilder对应的方法如下:

        @Override
    public int indexOf(String str) {
        return super.indexOf(str);
    }

    @Override
    public int indexOf(String str, int fromIndex) {
        return super.indexOf(str, fromIndex);
    }

    @Override
    public int lastIndexOf(String str) {
        return super.lastIndexOf(str);
    }

    @Override
    public int lastIndexOf(String str, int fromIndex) {
        return super.lastIndexOf(str, fromIndex);
    }

    @Override
    public StringBuilder reverse() {
        super.reverse();
        return this;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值