例1:
short x = 1; // 1
int i = 1; // 2
x += i; // 3
x = x + i; // 4
此时源码第4行编译器会报错:
Type mismatch: cannot convert from int to short
那么第3行与第4行有什么区别? 这个只能通过JVM指令分析了,我们可以编译一下前三行代码,即:
short x = 1; // 1
int i = 1; // 2
x += i; // 3
通过编译器得到指令源码如下:
short x = 1;
// 0 0:iconst_1
// 1 1:istore_1
int i = 1;
// 2 2:iconst_1
// 3 3:istore_2
x += i;
// 4 4:iload_1
// 5 5:iload_2
// 6 6:iadd
// 7 7:int2short
// 8 8:istore_1
// 9 9:return
最核心的是就是第7行指令,该指令是将int类型转short。所以可以最终可以成功,但是那么
x = x + i;
为什么失败?其实这是编译器为了避免数据精准的丢失,所以编译不通过,但是如果我们强制将结果转成short的话是不是就可以成功了呢?答案是:是的。
x = (short)(x + i);
结论:当+=使用在两个长度不一致的类型时,并且将结果由长类型赋值给短类型的话,JVM会自动帮助我们强制转类型。
例2:
Object x = 1;
String i = "";
x += i;
x = x + i;
网上有说报错:
The operator += is undefined for the argument type(s) Object, String
但是这个亲测是可以成功通过的,还是直接看JVM指令码:
Object x = Integer.valueOf(1);
// 0 0:iconst_1
// 1 1:invokestatic #2 <Method Integer Integer.valueOf(int)>
// 2 4:astore_1
String i = "";
// 3 5:ldc1 #3 <String "">
// 4 7:astore_2
x = (new StringBuilder()).append(x).append(i).toString();
// 5 8:new #4 <Class StringBuilder>
// 6 11:dup
// 7 12:invokespecial #5 <Method void StringBuilder()>
// 8 15:aload_1
// 9 16:invokevirtual #6 <Method StringBuilder StringBuilder.append(Object)>
// 10 19:aload_2
// 11 20:invokevirtual #7 <Method StringBuilder StringBuilder.append(String)>
// 12 23:invokevirtual #8 <Method String StringBuilder.toString()>
// 13 26:astore_1
x = (new StringBuilder()).append(x).append(i).toString();
// 14 27:new #4 <Class StringBuilder>
// 15 30:dup
// 16 31:invokespecial #5 <Method void StringBuilder()>
// 17 34:aload_1
// 18 35:invokevirtual #6 <Method StringBuilder StringBuilder.append(Object)>
// 19 38:aload_2
// 20 39:invokevirtual #7 <Method StringBuilder StringBuilder.append(String)>
// 21 42:invokevirtual #8 <Method String StringBuilder.toString()>
// 22 45:astore_1
通过查看指令可以发现直接就调用了String的拼接方法进行字符串拼接。
例3:
工具方法:
public static String randomString() {
return UUID.randomUUID().toString();
}
代码:
String val1 = randomString();
String val2 = randomString();
String val3 = randomString();
String val4 = randomString();
String val5 = val1 + val2 + val3 + val4 + val1;
String val6 = new StringBuilder().append(val1).append(val2).append(val3).append(val4).append(val1).toString();
val5与val6谁的拼接效率高?相信很多人可能会说是val6,但是实际上效率是一样的。还是看JVM指令:
String val1 = randomString();
// 0 0:invokestatic #15 <Method String randomString()>
// 1 3:astore_0
String val2 = randomString();
// 2 4:invokestatic #15 <Method String randomString()>
// 3 7:astore_1
String val3 = randomString();
// 4 8:invokestatic #15 <Method String randomString()>
// 5 11:astore_2
String val4 = randomString();
// 6 12:invokestatic #15 <Method String randomString()>
// 7 15:astore_3
String val5 = (new StringBuilder()).append(val1).append(val2).append(val3).append(val4).append(val1).toString();
// 8 16:new #4 <Class StringBuilder>
// 9 19:dup
// 10 20:invokespecial #5 <Method void StringBuilder()>
// 11 23:aload_0
// 12 24:invokevirtual #7 <Method StringBuilder StringBuilder.append(String)>
// 13 27:aload_1
// 14 28:invokevirtual #7 <Method StringBuilder StringBuilder.append(String)>
// 15 31:aload_2
// 16 32:invokevirtual #7 <Method StringBuilder StringBuilder.append(String)>
// 17 35:aload_3
// 18 36:invokevirtual #7 <Method StringBuilder StringBuilder.append(String)>
// 19 39:aload_0
// 20 40:invokevirtual #7 <Method StringBuilder StringBuilder.append(String)>
// 21 43:invokevirtual #8 <Method String StringBuilder.toString()>
// 22 46:astore 4
StringBuilder val6 = new StringBuilder();
// 23 48:new #4 <Class StringBuilder>
// 24 51:dup
// 25 52:invokespecial #5 <Method void StringBuilder()>
// 26 55:astore 5
val6.append(val1).append(val2).append(val3).append(val4).append(val1);
// 27 57:aload 5
// 28 59:aload_0
// 29 60:invokevirtual #7 <Method StringBuilder StringBuilder.append(String)>
// 30 63:aload_1
// 31 64:invokevirtual #7 <Method StringBuilder StringBuilder.append(String)>
// 32 67:aload_2
// 33 68:invokevirtual #7 <Method StringBuilder StringBuilder.append(String)>
// 34 71:aload_3
// 35 72:invokevirtual #7 <Method StringBuilder StringBuilder.append(String)>
// 36 75:aload_0
// 37 76:invokevirtual #7 <Method StringBuilder StringBuilder.append(String)>
// 38 79:pop
String val7 = val6.toString();
// 39 80:aload 5
// 40 82:invokevirtual #8 <Method String StringBuilder.toString()>
// 41 85:astore 6
阅读指令码即可得知结论效率一样。
例4:
方法1:
public static void testStringLoop() {
String str ="";
for (int i = 0; i <10 ; i++) {
str=str+randomString();
}
}
方法2:
public static void testStringBuilderLoop() {
StringBuilder builder =new StringBuilder();
for (int i = 0; i <10 ; i++) {
builder.append(randomString());
}
String str=builder.toString();
}
谁的效率高?答案方法2.具体自行看指令码:
public static void testStringLoop()
{
String str = "";
// 0 0:ldc1 #3 <String "">
// 1 2:astore_0
for(int i = 0; i < 10; i++)
//* 2 3:iconst_0
//* 3 4:istore_1
//* 4 5:iload_1
//* 5 6:bipush 10
//* 6 8:icmpge 38
str = (new StringBuilder()).append(str).append(randomString()).toString();
// 7 11:new #4 <Class StringBuilder>
// 8 14:dup
// 9 15:invokespecial #5 <Method void StringBuilder()>
// 10 18:aload_0
// 11 19:invokevirtual #7 <Method StringBuilder StringBuilder.append(String)>
// 12 22:invokestatic #15 <Method String randomString()>
// 13 25:invokevirtual #7 <Method StringBuilder StringBuilder.append(String)>
// 14 28:invokevirtual #8 <Method String StringBuilder.toString()>
// 15 31:astore_0
// 16 32:iinc 1 1
//* 17 35:goto 5
// 18 38:return
}
public static void testStringBuilderLoop()
{
StringBuilder builder = new StringBuilder();
// 0 0:new #4 <Class StringBuilder>
// 1 3:dup
// 2 4:invokespecial #5 <Method void StringBuilder()>
// 3 7:astore_0
for(int i = 0; i < 10; i++)
//* 4 8:iconst_0
//* 5 9:istore_1
//* 6 10:iload_1
//* 7 11:bipush 10
//* 8 13:icmpge 30
builder.append(randomString());
// 9 16:aload_0
// 10 17:invokestatic #15 <Method String randomString()>
// 11 20:invokevirtual #7 <Method StringBuilder StringBuilder.append(String)>
// 12 23:pop
// 13 24:iinc 1 1
//* 14 27:goto 10
String str = builder.toString();
// 15 30:aload_0
// 16 31:invokevirtual #8 <Method String StringBuilder.toString()>
// 17 34:astore_1
// 18 35:return
}