Java中i=i++;运算结果

本文深入探讨了Java中自增运算符的执行流程及其背后的秘密,揭示了为何i=i++;这样的表达式最终会得到i=0的结果。通过解析Java虚拟机(JVM)的运行机制,解释了赋值运算符的执行顺序和内存空间的作用,同时对比了不同编程语言处理类似问题的方式。

今天看到一个题,结果和原本想的不太一样,也有些意思,同时也深入地考虑到更多情况。
原本的题大体如下,
以下程序的输出结果是什么?
Class Test{
  public static void main(String [] args){
      int i = 0;
      i = i++;
      System.out.println(“i=”+i);
   }
}
答案是 i=0;
刚开始是思考的时候认为答案是i=1,到来是看答案是1,不信,又自己写了代码,果然是0,却不清楚原因,后来和同学讨论了下,猜想是编译器的原因。
这段代码的在编译的过程中为赋值语句的左边可以看作设置了一个临时变量,i=i++运算过程可分解如下:(临时变量设置为temp)
temp = i++;(temp = 0,这一部可以分解为temp = i;i++;)
i = temp;(i=0)
后来在网上查了一下,根据java中JVM对这道题有以下解析(引用http://www.cnblogs.com/wangjisi/archive/2010/06/06/1752600.html)
jvm里面有两个存储区,一个是暂存区(是一个堆栈,以下称为堆栈),另一个是变量区。
语句istore_1是将堆栈中的值弹出存入相应的变量区(赋值);语句iload_1是将变量区中的值暂存如堆栈中。
因为i = i++;是先将i的值(1)存入堆栈,然后对变量区中的i自加1,这时i的值的确是2,但是随后的istore_1又将堆栈的值(1)弹出赋给变量区的i,所以最后i =1。
又因为i = ++i;是先对变量区中的i自加1,然后再将变量区中i的值(2)存入堆栈,虽然最后执行了istore_1,但也只是将堆栈中的值(2)弹出赋给变量区的i,所以i = ++i;的结果是i = 2。

在C#中也有同样的问题,值是也是0。但是c/c++的运算结果却是 1.
原因是c/c++中没有另外设置一个临时变量或是临时空间来保存i,所有操作都是在一个内存空间中完成的。

以下是在网上搜索到的关于该问题的一些解析:
http://www.cnblogs.com/wangjisi/archive/2010/06/06/1752600.html
http://deshell.blog.163.com/blog/static/14095443420108165240503/?fromdm&isFromSearchEngine=yes
http://piaoboqiu.blog.163.com/blog/static/123127827200910192122472/


实例:

public class test1  
{  
    
  
    public static void main(String[] args)  
    {  
    	int i = 0;int j =0;
    	//Java 赋值符号 运算顺序 是从右至左
    	//j = i = i+1; 运算结果:i=1,j=1
        //j = i++; //转换成 i=0; j =i; i=i+1; 运算结果是: j=0; i=1;
        j = ++i;  //运算结果是: j =1; i =1
        System.out.println("i="+i+"j="+j);
    }  
}  
<pre name="code" class="java">class B{
	

	public static void main(String[] args){
		int i = 0;
		int j;
		//j = i = i++;  Java中的运算符优先级: = 从右只左 
		i = i++; //i= i++   等价于=> temp = i; i=i+1; i = temp;
		j = i;
		System.out.println("j="+j+"  i=" + i);
	}
}

Java 运算符优先级:
 
<img src="https://img-blog.youkuaiyun.com/20150203092744494?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvenFzNjI3NjExMzA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

<think>嗯,用户想了解Java中自增操作符的优先级和执行顺序,特别是像表达式int j = i++ + ++i * i++这样的复杂情况。首先,我需要回忆一下Java运算符的优先级规则。自增运算++属于一元运算符,优先级应该比加减乘除高,但后缀和前缀的优先级是否有区别呢?记得后缀的优先级比前缀更高,这可能影响表达式的解析顺序。 然后,用户提供的例子中有i++++i和i++的组合,还有乘法和加法。根据运算符优先级,乘法*的优先级高于加法+,所以应该先计算++i * i++这部分。但自增操作符的求值顺序也很重要,因为它们的副作用(即变量值的改变)何时发生会影响结果。 接下来需要考虑的是操作数的求值顺序。Java中操作数的求值是从左到右的,即使运算符优先级不同,操作数还是先按顺序计算。例如,在i++ + ++i * i++中,先计算左边的i++,然后计算右边的++i和i++,但乘法优先级更高,所以整体结构是i++加上(++i乘以i++)。 然后,具体到每个自增操作。假设i的初始值为0,比如: 1. 计算i++(后缀):这里会先取i的值0作为这个操作数的结果,然后i自增到1。 2. 计算++i(前缀):i先自增到2,然后取值为2。 3. 计算i++(后缀):取当前i的值2,然后i自增到3。 所以乘法部分是2 * 2 =4,然后加上最初的i++结果0,总和是4,所以j=4,此时i最终是3。 但这里可能需要分步解析。例如,原式拆解为: temp1 = i++(temp1=0,i变成1) temp2 = ++i(i先增到2,temp2=2) temp3 = i++(temp3=2,i变成3) 然后计算temp2 * temp3 = 2*2=4 最后j= temp1 + 4 =0 +4=4,i=3。 另外,用户提供的引用中有提到,比如引用3中说明后缀自增是先返回值再自增,前缀是先自增再返回值。所以这些规则需要应用到每一步中。 可能还需要注意运算符的优先级,例如后缀++的优先级高于前缀++吗?根据引用1中的例子,C++中的后缀优先级高于前缀,Java可能类似。所以在表达式i++ + ++i中,i++会被优先解析,然后是++i。 不过,在Java中,运算符优先级表中,后缀++的优先级是15,而前缀++的优先级是14,所以确实后缀更高。因此,在表达式中的结合方式可能需要考虑。 总之,正确的步骤应该是: 1. 确定每个自增操作的位置(前缀或后缀)及其优先级。 2. 根据操作符优先级和结合性分解表达式。 3. 按照从左到右的顺序计算每个操作数,考虑副作用的发生时间。 4. 最后计算结果。 此外,用户的问题还涉及到优先级和执行顺序的区别。优先级决定了表达式的结构,即哪些操作符先结合到操作数,而求值顺序则是操作数被计算的顺序,这里Java是严格从左到右的。 最后,需要提醒用户在实际编码中避免写出这样的复杂表达式,因为可读性差且容易出错。</think>### Java自增运算符优先级与执行顺序解析 在Java中,自增运算符$i++$(后缀)和$++i$(前缀)的优先级不同,且具有副作用(会改变变量值)。以下通过示例$j = i++ + ++i \times i++$逐步解析。 --- #### **1. 运算符优先级规则** - **后缀自增$i++$**:优先级**15**(最高级) - **前缀自增$++i$**:优先级**14** - **乘法$\times$**:优先级**12** - **加法$+$**:优先级**11** 根据优先级,表达式会被解析为: $$j = (i++) + \left( (++i) \times (i++) \right)$$ --- #### **2. 操作数求值顺序** Java严格遵循**从左到右**的求值顺序,即使运算符优先级不同。具体步骤如下(假设初始$i=0$): 1. **计算第一个$i++$**: - 取当前值$i=0$,之后$i$自增为$1$。 - **结果**:$0$,此时$i=1$。 2. **计算$++i$**: - $i$先自增为$2$,之后取值为$2$。 - **结果**:$2$,此时$i=2$。 3. **计算第二个$i++$**: - 取当前值$i=2$,之后$i$自增为$3$。 - **结果**:$2$,此时$i=3$。 4. **执行乘法**: - $(++i) \times (i++) = 2 \times 2 = 4$。 5. **执行加法**: - $j = 0 + 4 = 4$,最终$i=3$。 --- #### **3. 关键结论** - **副作用顺序**:每个自增操作的副作用(变量修改)在表达式求值过程中**立即生效**。 - **优先级 vs 执行顺序**:优先级决定表达式结构,但操作数求值始终从左到右[^3]。 --- #### **实际代码验证** ```java public class Main { public static void main(String[] args) { int i = 0; int j = i++ + ++i * i++; System.out.println("j=" + j + ", i=" + i); // 输出 j=4, i=3 } } ``` --- #### **编程建议** - **避免复杂表达式**:类似$i++ + ++i \times i++$的代码可读性差且易出错。 - **分解步骤**:明确拆分自增操作,例如: ```java int term1 = i++; // term1=0, i=1 int term2 = ++i; // term2=2, i=2 int term3 = i++; // term3=2, i=3 j = term1 + term2 * term3; // j=0+2*2=4 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值