A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 刘蕴学 中级黑马   /  2012-5-15 20:21  /  6885 人查看  /  34 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 了无尘 于 2012-5-17 07:10 编辑

关于自增和自减的第四题,我估计大家也学到些东西,当然老程序员都会。
今天的第五题是
int x = ?;
System.out.println(x << 32);
其中?为任意数,问题是,为什么x << 32还是x?

起来晚了,所以。。。还是不废话了,一下答案摘自我的个人笔记
初中毕业的桑不起啊,语文是体育老师教的,第四题我就表达不清楚,这回还是上代码通俗易懂
  1. public static void main(String[] args)
  2.         {
  3.                 //位运算符
  4.                 // << 左移运算符
  5.                 //5 的二进制是 0000 0101
  6.                 //左移一位的话0000 1010
  7.                 //5 左移一位是10,是不是相当于5*2
  8.                 System.out.println(5 << 1);
  9.                 //3左移一位正好是6
  10.                 System.out.println(3 << 1);
  11.                 //3左移两位是12,也就是*4
  12.                 System.out.println(3 << 2);
  13.                 //对比下,其实这个表达式跟上方的位移的结果
  14.                 //是一致的,运算效率上却要慢很多,这里只是
  15.                 //描述下,左移相当于乘上2的几次幂
  16.                 System.out.println((int)(3 * Math.pow(2, 2)));
  17.                 //下边发现左移0和32还是5,为什么呢?
  18.                 System.out.println(5 << 0);
  19.                 System.out.println(5 << 32);
  20.                 //木哈哈,这个绝对大杀器,为什么-1是31,-2是30?
  21.                 System.out.println(5 << -1);
  22.                 System.out.println("====================================>");
  23.                
  24.                 //打印一下x的位移情况,发现左移32位,x还是
  25.                 //原值,为什么会这样?
  26.                 //分析下最后几行,发现,并不是逐位补位的,
  27.                 //最后一行的像突然插进去的一样。
  28.                 int x = 7;
  29.                 for (int shift = 0; shift <= 32; shift++)
  30.         {
  31.                 System.out.println(getIntegerToBinary(x << shift));
  32.         }
  33.                 System.out.println("====================================>");
  34.                 //到这里可以看见,貌似从32开始,又开始像0-31
  35.                 //那样子逐位位移了,到第64次的时候又会在继续
  36.                 //这看起来是不是像模运算呢?
  37.                 //其实这不难理解,比如没有这个现象的话,咱就单
  38.                 //说位移,32位之后就都是0了吧,显然没有意义,
  39.                 //对于一个int的有效位移次数仅是0-31
  40.                 System.out.println(getIntegerToBinary(x << 33));
  41.                 System.out.println("====================================>");
  42.                 //事实证明,猜想是对的,但问题是,真的是这样?
  43.                 //模运算是很慢的,如果真是这样,位移操作还能比
  44.                 //乘法快?
  45.                 for (int shift = 0; shift <= 32; shift++)
  46.         {
  47.                 System.out.println(getIntegerToBinary(x << shift % 32));
  48.         }
  49.                 System.out.println("====================================>");
  50.                 //既然有效位移次数是0-31,那么31的2进制是什么?
  51.                 //是11111五个一,咱是不是只需要拿到位移次数的
  52.                 //低五位就可以了?你可以打印下0-64的2进制,看看
  53.                 //后5位是什么情况
  54.                 //如果这个实在难以理解,你就当成是32进制,每次取
  55.                 //这个数的32进制的个位数
  56.                 for (int shift = 0, mask = 0x0000001f; shift <= 32; shift++)
  57.         {
  58.                 System.out.println(getIntegerToBinary(x << (shift & mask)));
  59.         }
  60.                 System.out.println("====================================>");
  61.                 //这个眼熟不?如果 % 的方式是对的?左移-1位你怎么
  62.                 //解释?当然你理解成0相当于32,-1相当于31这是可以
  63.                 //但是,你怎么解释-1和31的关系?有什么证据?
  64.                 //总不能说-1%32是31,那还不让人笑掉大牙?
  65.                 //-1 & 0x0000001f是多少?取后五位正好是31
  66.                 System.out.println(getIntegerToBinary(x << (-1 % 32)));
  67.                 System.out.println(getIntegerToBinary(x << (-1 & 0x0000001f)));
  68.                 //将上边的两行化简,最后就是这样的了,结果一样,那
  69.                 //也就是说-1被处理,跟%没有一毛钱关系,问题发生在
  70.                 //-1怎么变成31,呵呵,已经很明显了吧?
  71.                 System.out.println(getIntegerToBinary(x << -1));
  72.                 System.out.println(getIntegerToBinary(x << 31));
  73.                 System.out.println("====================================>");
  74.         }
  75.         
  76.         public static final String DEFAULT_INT_ZERO = "00000000000000000000000000000000";
  77.         public static final String getIntegerToBinary(int value)
  78.         {
  79.                 String binary = Integer.toBinaryString(value);
  80.                 int length = 32 - binary.length();
  81.                 return DEFAULT_INT_ZERO.substring(0, length) + binary;
  82.         }
复制代码

评分

参与人数 2技术分 +2 黑马币 +30 收起 理由
职业规划-刘倩老师 + 1 + 30 支持+赞赞赞!!!
贠(yun)靖 + 1

查看全部评分

34 个回复

倒序浏览
本帖最后由 高云飞 于 2012-5-15 20:38 编辑

因为java的int类型在内存中占用4个字节,也就是32bit,<<不足的位置上,用原来的数补齐,相当于循环左移32位后,每一位上的数又回到原来的位置上了,当然还是原来的x了。

点评

事实上,你这个答案是错的  发表于 2012-5-15 20:39
回复 使用道具 举报
可不可以这么回答,因为Int只有32位,当移动位数大于32的时候,就会对移动位数对32求余,再进行移位运算。而32就是刚好不移。。。。

点评

呵呵,我都说了,%这种说法不行,跟实际不符,但理解的话没问题  发表于 2012-5-15 21:02
回复 使用道具 举报
以前看过,貌似  int类的  x<<n等价于 x<<n%32....所以x<<32  =  x<<(32%32) =   x<<0  就不变

点评

呵呵,我都说了,%这种说法不行,跟实际不符,但理解的话没问题  发表于 2012-5-15 21:03
回复 使用道具 举报
还有 int  x>>n和  x>>>n也是同个道理,long好像是  x>>(n%64)

点评

呵呵,我都说了,%这种说法不行,跟实际不符,但理解的话没问题  发表于 2012-5-15 21:03
回复 使用道具 举报
1) 如果x是byte, short, char类型, 则将x提升为int;

  2) 如果x是byte, short, char, int类型, 则n被重新赋值(过程是:取n的补码的低5位再转成十进制的int值,相当对n取32模: n=n%32);

  如果x是long型, 则n被重新赋值(过程是:取n的补码的低6位再转成十进制的int值,相当对n取64模: n=n%64);

  (因为int类型为4个字节,即32位,移动32位将没有任何意义.对于long则是模64)

  3) 对x左移n个位数, 整个表达式产生一个新值(x的值不变);

  <<是左移符号,列x<<1,就是x的内容左移一位(x的内容并不改变)

  >>是带符号位的右移符号,x>>1就是x的内容右移一位,如果开头是1则补1,是0责补0,(x的内容并不改变).

  >>>是不带符号位的右移,x>>>1就是x的内容右移一位,开头补0(x的内容并不改变)

点评

骚年,你的答案跟题根本就不搭边  发表于 2012-5-15 22:11
回复 使用道具 举报
好吧 我表示崩溃  肿么那规则来出问题呢?!

点评

很简单的小问题,看过老毕第二天的答不出来只能说明没认真学  发表于 2012-5-15 22:10
回复 使用道具 举报
冯心程 黑马帝 2012-5-15 21:09:08
8#
这题我会啊 分给我留着老师

数用32位表示 假如这个数是3那么它再计算机中32位是这样的
0000-0000 0000-0000 0000-0000 0000-0011
假如这个数在电视屏幕里从左到右布满 如果向左移动2位 前面消失的两个0就在数的后面补上  。。。(比喻的还算恰当吧、、)
当移动到31位的时候第一个1从左面消失但是从后面补上   向左移动完32位后最后一个1也从左面消失但补在后面  

所以向左移动32位后的结果和移动前是一样的  

点评

System.out.println(Integer.toBinaryString(7 << 31)); 你可以自己试下,看看是不是这样  发表于 2012-5-15 21:13
回复 使用道具 举报
冯心程 黑马帝 2012-5-15 21:24:57
9#
冯心程 发表于 2012-5-15 21:09
这题我会啊 分给我留着老师

数用32位表示 假如这个数是3那么它再计算机中32位是这样的

晕 最低位用0补  我再缕缕

点评

骚年,3分不是那么好拿的,我也不会这么帮大伙刷分的,要不然老师就先把我干掉了  发表于 2012-5-15 22:04
回复 使用道具 举报
{:soso_e126:}崩溃了·~难道32没意义JVM就不算了~~~~
求答案..

点评

很简单的小问题,看过老毕第二天的答不出来只能说明没认真学  发表于 2012-5-15 22:09
回复 使用道具 举报
实验了一下:
1.   byte x=5;
System.out.println(x<<8);
输出是0
2.   int x=5;
System.out.println(x<<64);
输出是5
3.   byte x=5;
System.out.println(x<<32);
输出是5
4.   int x=5;
System.out.println(x<<31);
输出是-2147483648
所以前面说的位移32位又刚好回到原来的数的观点肯定不对
那么原因可能是因为int和long在位移运算的时候只有低五位,低6位才会有用,也就是说位移超过31和63就会无效运算
byte,short在位移的时候会自动转成int,所以就能解释为什么我开始实验的时候出现的结果了。
回复 使用道具 举报
冯心程 发表于 2012-5-15 21:24
晕 最低位用0补  我再缕缕

老师V5  给跪了  求答案:loveliness:

点评

俺不是老师。。。  发表于 2012-5-15 22:15
回复 使用道具 举报
本帖最后由 于陈 于 2012-5-15 22:16 编辑

半对额.......我都不知道哪一半对了...我再想想.....老师这个问题真心很伤啊~去看下老毕第二天了
回复 使用道具 举报
冯心程 发表于 2012-5-15 22:06
老师V5  给跪了  求答案

比我强的都是老师  不要谦虚  么么哒:loveliness:
果断滚回去看视频了  看完答出来分还算我的中不:loveliness:
回复 使用道具 举报
<<(左移运算符):是将左操作数向左移动右操作数指定的位数,右边移出的空位以0填充。
而当左操作数为int类型时,移位运算符右侧的操作数只有低5位是有效的(低5位的十进制最大值为31),
因为int类型只有32位,这样就可以避免将数据全部移出而失去意义。
我假如题目中的x为27,即现在是要计算27<<32。所以我们先取右侧操作数的低5位,32的补码为:
0000-0000 0000-0000 0000-0000 0010-0000
提取低5位后为:00000,这也即是十进制的0,所以,27<<32相当于:27<<0。
也即是x移动0位,所以x<<32仍然是x。

评分

参与人数 2技术分 +2 黑马币 +2 收起 理由
贠(yun)靖 + 2
冯心程 + 2 精神上支持你

查看全部评分

回复 使用道具 举报
本帖最后由 于陈 于 2012-5-15 22:40 编辑

根据毕老师说的:左移运算就是乘以2的移动位数次幂
                          3<<1  就是3*2的1次方
                         3<<2  就是3*2的2次方
                         3<<3  就是3*2的3次方
                         .......
                         3<<31 就是3*2的31次方
                         3<<32就是3*2的0次方  2的0次方就是1,x*1不就等于x么?
                        
                         3<<33就是3*2的1次方
是这样么?

点评

错,你又把想到的那点答案抛弃了  发表于 2012-5-15 22:41
回复 使用道具 举报
于陈 发表于 2012-5-15 22:35
根据毕老师说的:左移运算就是乘以2的移动位数次幂
                          3

啊啊啊啊....悲剧...我再去仔细看下视频~要学校断网了,看来只能明天了~
回复 使用道具 举报
手慢了  和15楼想的一样  他说的对吧  我是与分无缘了{:soso_e199:}
回复 使用道具 举报
关于这道题,我的开始的想法是可能是java内存中可能会有一块区域存储x的原始的值。

1.   但之后我查阅了Thinking in java 发现一段话:
       “对char, byte或者short进行移位处理,那么在移位进行之前,它们会自动转换成一个int,得到的也是一个int类型的值只有数值右侧的低5个低位才会有用。这样可防止我们位移超过int型所具有的位数。若对一个long类型的的数值进行处理,最后得到的结果也是long。此时只会用到数值右端的低6位
                                                                                                    ————(机械工艺出版社,java编程思想第四版,50页)


这是书中的原文,我感觉翻译的不是很好,很晦涩。但是我们应该能够理解其内容:
这段话即是说当遇到X<<32情况,只有32的二进制形式(100000)的后五位有效,即x<<32等于x<<0。所以我们发现它x<<32会打印出x的原始值。

2.    同样我也对这段话中提到的其他类型进行了验证(long左移64位,其他类型左移32位):
        long  x =3;
        char  c =5;
        byte  b =7;
        short s= 9;
        System.out.println(x<<64);
        System.out.println(c<<32);
        System.out.println(b<<32);
        System.out.println(s<<32);       

得到的结果仍然为:3 5 7 9 可以基本说明这段话是正确的。

1.jpg (80.42 KB, 下载次数: 102)

1.jpg

评分

参与人数 1技术分 +1 收起 理由
贠(yun)靖 + 1 赞一个!

查看全部评分

回复 使用道具 举报
看来 我学的不认真啊 从头再看一遍吧
回复 使用道具 举报
12下一页
您需要登录后才可以回帖 登录 | 加入黑马