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;
}