黑马程序员技术交流社区

标题: 关于i=i++神奇面试题 [打印本页]

作者: hkh3321313    时间: 2016-3-22 23:10
标题: 关于i=i++神奇面试题
今天上课的时候提到一个很有意思的现象,老师的讲解不是很明白,现在和大家分享一下网上的理解.class Demo {
public static void main(String [] args){
int i=0;

for(int j=0;j<=100;j++){

    i=i++;
  }
System.out.println("i="+i);

}
}
一开始我也以为最终结果为i=100,实际的结果是i=0.为什么会出现这样的结果呢?
原来是在编译器上出了问题,java的编译器在遇到i++和i- -的时候会重新为变量运算分配一块内存空间,以存放原始的值,而在完成了赋值运算之后,将这块内存释放掉,下面首先看一下如果是j=i++的情况:

i的原始值存放在后开辟的内存中,最后这个值将赋值给j,这样j=i++后,j就会得到i的值,而i又将自加,所以,在释放内存之后,原来存放j和i的地方将得到值将是:j(此时的值等于初始i值)和i(i自加后的值)。
明白了上面的问题,让我们接下来看看i=i++的情况:



所以这样最后一次循环内的结果仍旧是i(即0)。

而C语言中的i=i++就只是完成i++的内容,所以结论会不同。这种情况说明java和c的处理语法的机制不同,如果在程序中只输入i++就不会出现这个方面的问题,所以大家在以后的程序中如果使用到i=i++的时候要格外小心,一般只需要用i++就不会有问题了.



作者: huangkai521    时间: 2016-3-22 23:35
学习了,涨姿势,
作者: Gqg    时间: 2016-3-22 23:53
长知识了
作者: xiaofushen    时间: 2016-3-23 00:18
这个问题一开始我和同学也纠结好久,不过后来明白了,不过楼主分享的很详细,理解又加深了.
作者: 赵国政    时间: 2016-3-23 00:38
够牛逼的!
作者: zhoubinjian    时间: 2016-3-23 00:42
自我测试那里有一道这样的题。。。我错了
作者: Ak-47    时间: 2016-3-23 01:45
刚学基础但还是看的不是很懂啊
作者: zhoubinjian    时间: 2016-3-23 02:00
不行了,还是没有理解过来 ,,内存上的i+1,是怎么回事,怎么是i赋值给i+1的呢,
作者: Banana_uSuOO    时间: 2016-3-23 08:21
还没太懂!
作者: 淡然无味    时间: 2016-3-23 09:21
i++和++i傻傻分不清
作者: yijincheng    时间: 2016-3-23 09:26
不错,受教了
作者: 赵竹子    时间: 2016-3-23 13:29
还是不太懂
作者: lijiy09    时间: 2016-3-23 13:48
厉害,学习学习~
作者: 695010894    时间: 2016-3-23 13:55
本帖最后由 695010894 于 2016-3-23 14:01 编辑

你这个 i=i++;是先 赋值再自增(自增后并不存在赋值操作),如果写成  i=++i;或者直接i++;而且0-100结果是101。
作者: LLQALLQ    时间: 2016-3-23 14:47
很厉害 赞一个!!!
作者: 我是你岁哥❤环    时间: 2016-3-23 15:05
学习了,谢谢
作者: 「AτS」    时间: 2016-3-23 16:51
之前看过类似的问题,时间久了就忘了,这次收藏起来,get!
作者: CangYe    时间: 2016-3-23 22:13
这种陷阱好容易坑人啊!
作者: 萌萌的_O30IH    时间: 2016-3-23 22:33
真的吗?我试试
作者: 北极1989    时间: 2016-3-23 23:31
我也以为是100,长见识了,这个题目分享的好
作者: hkh3321313    时间: 2016-3-24 00:04
huangkai521 发表于 2016-3-22 23:35
学习了,涨姿势,

我也是涨姿势了
作者: hkh3321313    时间: 2016-3-24 00:05
huangkai521 发表于 2016-3-22 23:35
学习了,涨姿势,

我也是涨姿势了
作者: hkh3321313    时间: 2016-3-24 00:07
xiaofushen 发表于 2016-3-23 00:18
这个问题一开始我和同学也纠结好久,不过后来明白了,不过楼主分享的很详细,理解又加深了. ...

实际上这个涉及了java虚拟机的低层机制,如果用C语言写出来结果又会完全不同.
而且,实际工作中谁这么写呀,太烧脑了~
作者: hkh3321313    时间: 2016-3-24 00:09
Ak-47 发表于 2016-3-23 01:45
刚学基础但还是看的不是很懂啊

仔细看看两张图,很好懂的~
作者: hkh3321313    时间: 2016-3-24 00:11
北极1989 发表于 2016-3-23 23:31
我也以为是100,长见识了,这个题目分享的好

我是对老师的解释很不理解,所以才上网搜了一下相关资料.这个是一道很著名的Java面试题,而且貌似大家都不是很懂...
作者: lovelife    时间: 2016-3-24 11:30
j=i++  就是看不懂啊 好难呀
作者: 天赐潇潇    时间: 2016-3-24 12:26
111111111111111111111111111111
作者: cohle1992    时间: 2016-3-24 12:44
学习了,很有用!
作者: 坚持到底    时间: 2016-3-24 12:47
长知识了....
作者: 坚持到底    时间: 2016-3-24 12:48
长知识了,
作者: lyy0525    时间: 2016-3-24 13:00
学习学习
作者: skxy2016    时间: 2016-3-24 13:34
个人理解:
java的编译器在遇到++和- -的时候会在栈内存中重新为变量分配一块内存空间作为运算,如果是i = i++,先将栈内存中i的初始值赋给堆内存的i,然后在栈内存中进行自增运算,运算结束也就销毁了,而i = ++i,则先在栈内存进行自增运算,运算结束赋值给堆内存中的i,然后销毁栈内存中的i;同理--也是一样的道理。通过以下代码可以验证:
public class Itest{
public static void main(String [] args){
int i=0;
int a=0;
a = a++;
System.out.println("a=" +a);//a = 0

a = ++a;
System.out.println("a="+ a);//a = 1

}
}
作者: fighting2016    时间: 2016-3-24 15:14
表示没看懂
作者: hkh3321313    时间: 2016-3-24 21:15
fighting2016 发表于 2016-3-24 15:14
表示没看懂

多看两遍,很好懂的~
作者: 874831352    时间: 2016-3-24 21:18
刚开始这个还不是很会呢
作者: 轰天雷    时间: 2016-3-24 21:19
题目非常好
作者: hkh3321313    时间: 2016-3-24 21:20
874831352 发表于 2016-3-24 21:18
刚开始这个还不是很会呢

这个属于比较难的,平时都不会很难,底层的东西我们不会学到的,那都是大牛学习的东西~
作者: hkh3321313    时间: 2016-3-24 21:21
skxy2016 发表于 2016-3-24 13:34
个人理解:
java的编译器在遇到++和- -的时候会在栈内存中重新为变量分配一块内存空间作为运算,如果是i  ...

哥们是不是计算机专业的呢?
作者: hkh3321313    时间: 2016-3-24 21:23
轰天雷 发表于 2016-3-24 21:19
题目非常好

大家互相学习呗
作者: sdx_1234    时间: 2016-3-24 21:25
顶  涨知识了啊
作者: jiangkaizhuo    时间: 2016-3-24 21:25
长姿势阿里
作者: wangze    时间: 2016-3-29 11:14
很容易忽略的一个知识点,我们考试的时候就考过,全班大部分人都错了。
作者: hydra    时间: 2016-3-29 11:22
学习了,涨姿势,
作者: a292723685    时间: 2016-3-29 12:33
刚学的时候我也纠结了很久
其实就是程序底层的运算顺序问题
....
作者: 丶黒貓    时间: 2016-3-29 18:57

作者: ZTK12345    时间: 2016-3-29 23:06
涨姿势,长知识,谢谢楼主分享
作者: dxw    时间: 2016-3-29 23:49
收藏了,好东西!!!!!!
作者: zixiyang    时间: 2016-3-30 00:03
zhoubinjian 发表于 2016-3-23 02:00
不行了,还是没有理解过来 ,,内存上的i+1,是怎么回事,怎么是i赋值给i+1的呢, ...

int i =0;
i = i++;
可分为2个式子看:
i=i; i=i+1;
在计算机底层运算是从右向左的,所以
先是 i=i+1,即i=1;  然后再i=i,即 i = 0;
这相当于做了一次重新赋值操作,因此结果还是0;
作者: 腾龙3158    时间: 2016-3-30 00:37
涨姿势了!
作者: 守徒徒    时间: 2016-3-30 01:30
学习了!!
作者: zx7750462    时间: 2016-3-30 11:36
感觉楼主的好麻烦,其实可以这样理解.
i=i++实际上等效于
temp=i;//temp=0
i=i+1;//i=1;
i=temp;//i=0;执行完这句话i还是等于0,不管循环多少次你都是在重复这个过程而已.i++的值还是没加之前的temp
实际上就是前++和后++的区别
作者: ipursue    时间: 2016-3-30 12:11
我觉得这种编译处理方式,不是很合适,违背了正常的逻辑。
作者: ruigao1993    时间: 2016-3-30 13:56
赋值问题,直接写++i;就行了,
i=++i;给i的赋值一直是0
作者: 小海龙    时间: 2016-3-30 14:37
长知识,自测题遇到过,不运行简直不敢相信。
作者: forzsh    时间: 2016-3-30 23:33
赞一个呗
作者: zapple926    时间: 2016-3-31 00:17
涨知识了
作者: 小海龙    时间: 2016-3-31 11:05
无论是++i还是i++其实都做了自加1这个运算,区别是是否参与运算
++i在自加1后直接参与运算。
而i++在自加1后,参与运算的是i未加1之前的值,
在当i++赋值给i时,将加1的值覆盖掉了,又变为原来的值了。
作者: hkh3321313    时间: 2016-3-31 11:06
zx7750462 发表于 2016-3-30 11:36
感觉楼主的好麻烦,其实可以这样理解.
i=i  实际上等效于
temp=i;//temp=0

我觉得我俩这个可以结合一下,更容易理解呢
作者: 只为编程    时间: 2016-3-31 11:20
涨姿势了
作者: 百里青山    时间: 2016-3-31 12:48
每天都逛帖,赞一个~很不错
作者: 604840337    时间: 2016-3-31 12:59
这道题老师讲了 还是每台明白 就背下来了
作者: cohle1992    时间: 2016-3-31 13:14
学习了!收藏!
作者: Yoyoqiu    时间: 2016-3-31 15:33
看不懂 ,
感觉
int i = 0 ;
i=i++  , i 先赋值 给左边  然后 自增  自增完了  还赋值 覆盖刚才的 i 吗 ?   看来是不赋值的 打印  i = 0
但是换成
a= i++,  先赋值给左边 然后自增  为什么这个自增后 打印就是 自增后的 1 呢  打印  i=1   a = 0
作者: 715596417    时间: 2016-3-31 15:47
长知识了。。。。
作者: 747844695    时间: 2016-3-31 19:37
不注意真会被坑
作者: 874831352    时间: 2016-4-1 07:01
学习学习吧
作者: youngrivers    时间: 2016-4-1 12:28
这个和编译器相关的
作者: lz19918888    时间: 2016-4-13 21:18
还不是很懂啊
作者: z736886202    时间: 2016-4-13 21:32
厉害,分析有够深的
作者: zlf1991312    时间: 2016-4-13 21:36
搜噶,了解了
作者: yy0328    时间: 2016-4-13 21:42
涨姿势了  谢谢
作者: zhouboyangliu    时间: 2016-4-13 21:54
学习一下        
作者: 小流氓    时间: 2016-4-13 22:10
不太明白感觉还是挺牛的
作者: 丶半度微凉    时间: 2016-4-13 22:11
zhoubinjian 发表于 2016-3-23 02:00
不行了,还是没有理解过来 ,,内存上的i+1,是怎么回事,怎么是i赋值给i+1的呢, ...

是指赋值给那块内存吧,就是i代替了i+1
作者: 丶半度微凉    时间: 2016-4-13 22:41
可以,涨姿势了,不细想一下还真是容易错
作者: NeverBack    时间: 2016-4-13 22:42
xiaofushen 发表于 2016-3-23 00:18
这个问题一开始我和同学也纠结好久,不过后来明白了,不过楼主分享的很详细,理解又加深了. ...

i = i++;不是先赋值然后再自增吗?我看那个内存图上是先自增然后赋值呢!!!
作者: xiaofushen    时间: 2016-4-13 23:17
NeverBack 发表于 2016-4-13 22:42
i = i++;不是先赋值然后再自增吗?我看那个内存图上是先自增然后赋值呢!!!

我们说的先赋值再自增是对于j=i++的情况,因为就结果而言,是先赋值再自增.对于底层的java编译器是如何实现这一操作的,我们并不知道,对于楼主发的java编译器对于i++的操作,就结果而言是和"j=i++先赋值再自增"不矛盾的.而对于i=i++,就不能认为是先赋值再自增了,因为底层是楼主发的内存图那样操作的.
作者: 李亚东_JAVAEE    时间: 2016-4-13 23:20
本来还挺懂得,这一下整蒙了
作者: Directly    时间: 2016-4-13 23:30
这个问题一开始我和同学也纠结好久,不过后来明白了,不过楼主分享的很详细,理解又加深了.
作者: kcufow    时间: 2016-4-14 09:30
学习学习
作者: jialianghao    时间: 2016-4-14 10:07
混淆视听,只要逻辑清楚就不会错了。不过刚开始看这道题还是会错的
作者: 84345992    时间: 2016-4-14 10:12
谢谢分享~
作者: lixianglei    时间: 2016-4-14 10:19
精华就是不一样 看不懂
作者: sensir    时间: 2016-4-14 21:40
看了一会才明白,

因为i= i ++; i是后加 是先拿出i的值,准备赋值给i ,然后i完成自增 此刻i是i + 1;最后完成赋值操作将拿出的 i 覆盖 i自增后的值。
第一次发现这个问题,老师没有讲。


作者: lrx    时间: 2016-4-14 22:09
可以的   赞
作者: 叶叶君    时间: 2016-4-14 22:27
自我测试那里有一道这样的题。。。我错了
作者: 大山的伤    时间: 2016-4-14 22:41
很详细,没遇到过!
作者: 大熊猫丶    时间: 2016-4-14 22:44
顶顶顶顶
作者: clvslyf    时间: 2016-4-15 10:41
来学习      
作者: 马儿不吃草    时间: 2016-4-15 14:31
for语句执行完之后就是从内存消失,i循环之后得到的值就不存在了.所以最后的值还是0,while和for的区别就在于要是循环之后还要使用那个变量就使用while循环,而for循环是不行的.
作者: Q灬先生    时间: 2016-4-15 23:41
顶一个~~~~~~
作者: west2179    时间: 2016-4-15 23:48
学习了。。。。。受益匪浅
作者: NB的笨小孩    时间: 2016-4-16 07:09
确实没注意过,现在知道原理了,谢谢楼主分享
作者: 编号89757    时间: 2016-4-16 07:58
还是不明白,这个涉及太底层的知识,没时间去专研
作者: yueyemisi    时间: 2016-4-16 16:00
i一直就是0啊 循环多少次都是
作者: weidong10heima    时间: 2016-7-13 19:47
我遇到过,自我测试那里有一道这样的题。
作者: zhangwenjin    时间: 2016-7-13 20:42
这个是特例 一定要记住
作者: longforus    时间: 2016-7-13 22:45
原来是这样的 学习了
作者: lsp0523    时间: 2016-7-13 22:49
这个是对的,先赋值后运算,i的值一直是0,
作者: chenlongwen    时间: 2016-7-13 22:52
学习了,涨姿势




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2