深入理解Java中i++和++i

在几乎所有的命令式编程语言中,必然都会有i++和++i这种语法。有些语言中i++和++i既可以作为左值又可以作为右值,在Java语言中,这两条语句都只能作为右值,而不能作为左值。同时,它们都可以作为独立的一条指令执行。

可以看到程序中 ++a =  5; 和 a++ = 5;报错了。 

下面说明i++和++i的实现原理:

首先写一个例子:

{
    int i = 1;
    int j1 = i++;
    System.out.println("j1=" + j1); // 输出 j1=1
    System.out.println("i=" + i); // 输出 i=2
}

{
    int i = 1;
    int j2 = ++i;
    System.out.println("j2=" + j2); // 输出 j2=2
    System.out.println("i=" + i); // 输出 i=2
}

由结果可以看出无论是i++和++i指令,对于i变量本身来说是没有任何区别,指令执行的结果都是i变量的值加1。而对于j1和j2来说,这就是区别所在。

int i = 1;
int j1 = i++; // 先将i的原始值(1)赋值给变量j1(1),然后i变量的值加1
int j1 = ++i; // 先将i变量的值加1,然后将i的当前值(2)赋值给变量j1(2)

 接下来让我们深入到编译后的字节码层面上来了解i++和++i的实现原理,为了方便对比,笔者将这两个指令分别放在2个不同的方法中执行,源代码如下:

public class Test {

    public void testIPlus() {
        int i = 0;
        int j = i++;
    }

    public void testPlusI() {
        int i = 0;
        int j = ++i;
    }

}

 将上面的源代码编译之后,查看编译生成的代码(忽略次要代码)如下:

...
{
  ... 

  public void testIPlus();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=3, args_size=1
         0: iconst_0               // 生成整数0
         1: istore_1               // 将整数0赋值给1号存储单元(即变量i)
         2: iload_1                // 将1号存储单元的值加载到数据栈(此时 i=0,栈顶值为0)
         3: iinc          1, 1     // 1号存储单元的值+1(此时 i=1)
         6: istore_2               // 将数据栈顶的值(0)取出来赋值给2号存储单元(即变量j,此时i=1,j=0)
         7: return                 // 返回时:i=1,j=0
      LineNumberTable:
        line 4: 0
        line 5: 2
        line 6: 7

  public void testPlusI();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=3, args_size=1
         0: iconst_0                // 生成整数0
         1: istore_1                // 将整数0赋值给1号存储单元(即变量i)
         2: iinc          1, 1      // 1号存储单元的值+1(此时 i=1)
         5: iload_1                 // 将1号存储单元的值加载到数据栈(此时 i=1,栈顶值为1)
         6: istore_2                // 将数据栈顶的值(1)取出来赋值给2号存储单元(即变量j,此时i=1,j=1)
         7: return                  // 返回时:i=1,j=1
      LineNumberTable:
        line 9: 0
        line 10: 2
        line 11: 7
}
...

下面举个面试题的例子如下: 

下面程序是否存在问题?如果存在,请指出问题所在,如果不存在,说明输出结果。
package www;

public class Test {
public static void main(String[] args) {
	Test test = new Test();
	int i =0;
	test.increase(i); //完成方法调用之后i = 0 ,因为方法increase是值传递,因此对形参的修改不会影响到实参的值。(参数列表里传进去的值为实参i的副本)
	/**
	 * i=++i;
	 */
	//上面代码出现警告The assignment to variable i has no effect 警告的意思是将值赋给变量i毫无作用,并不会改变i的值。也就是说:i = ++i等价于++i
	
	i=i++;
	System.out.println(i);
		
}

void increase(int i) {
	i++;
}
}

 该问题答案是不存在问题,输出结果为0

解释如下:

1、首先对方法increase的调用是值传递,参数列表里传的是实参的拷贝,因此在方法里对形参的修改不会影响到实参的值,所以在执行完increase方法的调用之后,main方法中i的值还是0。

2、对于i = i ++ ;

i++的实现原理为:

1、把变量i的值取出来,放在一个临时变量tmp里。

2、变量i执行自增操作。

3、把临时变量tmp的值作为自增运算的结果返回。

所以对于i = i++; 相当于执行了下面三行代码:

1)tmp=i; //把i的值保存到tmp ,tmp = 0

2)i = i + 1; //执行自增操作,i = 1

3)i= tmp; //将tmp的值赋值给i ,此时 i = 0

所以最终程序运行结果为0。

如果将 i = i ++ ; 变成 i = ++ i;则运行结果为 1 。 因为++i是先执行i自增,然后才赋值给左侧变量。

但同时Eclipse IDE中抛出【The assignment to variable i has no effect】警告,警告的意思是将值赋给变量i毫无作用,并不会改变i的值。也就是说:i = ++i等价于++i

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值