JAVA那些“坑”-你以为x+=i就等同于x=x+i?

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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值