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_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: new #2 // class java/lang/StringBuffer3: dup4: invokespecial #3 // Method java/lang/StringBuffer."<init>":()V7: astore_18: ldc #4 // String a10: astore_211: ldc #5 // String b13: astore_314: ldc #6 // String 2316: astore 418: ldc #7 // String 220: astore 522: new #8 // class java/lang/StringBuilder25: dup26: invokespecial #9 // Method java/lang/StringBuilder."<init>":()V29: aload 531: invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;34: ldc #11 // String 336: 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 644: new #8 // class java/lang/StringBuilder47: dup48: invokespecial #9 // Method java/lang/StringBuilder."<init>":()V51: aload_252: invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;55: aload_356: 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 764: new #8 // class java/lang/StringBuilder67: dup68: invokespecial #9 // Method java/lang/StringBuilder."<init>":()V71: astore 873: aload 875: iconst_176: invokevirtual #13 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;79: pop80: getstatic #14 // Field java/lang/System.out:Ljava/io/PrintStream;83: aload 485: invokevirtual #15 // Method java/io/PrintStream.println:(Ljava/lang/String;)V88: getstatic #14 // Field java/lang/System.out:Ljava/io/PrintStream;91: aload 693: invokevirtual #15 // Method java/io/PrintStream.println:(Ljava/lang/String;)V96: getstatic #14 // Field java/lang/System.out:Ljava/io/PrintStream;99: aload 4101: aload 6103: if_acmpne 110106: iconst_1107: goto 111110: iconst_0111: invokevirtual #16 // Method java/io/PrintStream.println:(Z)V114: return
}
- 可以看到String++符号操作底层用的是StringBuilder类中的append方法,最后再通过toString()方法进行实现的。
StringBuilder中的append()方法
- 可以看到方法中调用的是super中的append方法
@Overridepublic 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 codeif (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 iterationwhile (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对应的方法如下:
@Overridepublic synchronized int length() {
return count;}@Overridepublic synchronized int capacity() {
return value.length;}@Overridepublic synchronized void ensureCapacity(int minimumCapacity) {
super.ensureCapacity(minimumCapacity);}/*** @since 1.5*/@Overridepublic synchronized void trimToSize() {
super.trimToSize();}/*** @throws IndexOutOfBoundsException {@inheritDoc}* @see #length()*/@Overridepublic synchronized void setLength(int newLength) {
toStringCache = null;super.setLength(newLength);}/*** @throws IndexOutOfBoundsException {@inheritDoc}* @see #length()*/@Overridepublic synchronized char charAt(int index) {
if ((index < 0) || (index >= count))throw new StringIndexOutOfBoundsException(index);return value[index];}
StringBuilder对应的方法如下:
@Overridepublic int indexOf(String str) {
return super.indexOf(str);}@Overridepublic int indexOf(String str, int fromIndex) {
return super.indexOf(str, fromIndex);}@Overridepublic int lastIndexOf(String str) {
return super.lastIndexOf(str);}@Overridepublic int lastIndexOf(String str, int fromIndex) {
return super.lastIndexOf(str, fromIndex);}@Overridepublic StringBuilder reverse() {
super.reverse();return this;}