谜题27:变幻莫测的i值
与谜题26中的程序一样,下面的程序也包含了一个记录在终止前有多少次迭代的循环。与那个程序不同的是,这个程序使用的是左移操作符(<<)。你的任务照旧是要指出这个程序将打印什么。当你阅读这个程序时,请记住 Java 使用的是基于2的补码的二进制算术运算,因此-1在任何有符号的整数类型中(byte、short、int或long)的表示都是所有的位被置位:
public class Shifty {
public static void main(String[] args) {
int i = 0;
while (-1 << i != 0)
i++;
System.out.println(i);
}
}
常量-1是所有32位都被置位的int数值(0xffffffff)。左移操作符将0移入到由移位所空出的右边的最低位,因此表达式(-1 << i)将i最右边的位设置为0,并保持其余的32 - i位为1。很明显,这个循环将完成32次迭代,因为-1 << i对任何小于32的i来说都不等于0。你可能期望终止条件测试在i等于32时返回false,从而使程序打印32,但是它打印的并不是32。实际上,它不会打印任何东西,而是进入了一个无限循环。
问题在于(-1 << 32)等于-1而不是0,因为移位操作符之使用其右操作数的低5位作为移位长度。或者是低6位,如果其左操作数是一个long类数值[JLS 15.19]。
这条规则作用于全部的三个移位操作符:<<、>>和>>>。移位长度总是介于0到31之间,如果左操作数是long类型的,则介于0到63之间。这个长度是对32取余的,如果左操作数是long类型的,则对64取余。如果试图对一个int数值移位32位,或者是对一个long数值移位64位,都只能返回这个数值自身的值。没有任何移位长度可以让一个int数值丢弃其所有的32位,或者是让一个long数值丢弃其所有的64位。
幸运的是,有一个非常容易的方式能够订正该问题。我们不是让-1重复地移位不同的移位长度,而是将前一次移位操作的结果保存起来,并且让它在每一次迭代时都向左再移1位。下面这个版本的程序就可以打印出我们所期望的32:
public class Shifty {
public static void main(String[] args) {
int distance = 0;
for (int val = -1; val != 0; val <<= 1)
distance++;
System.out.println(distance);
}
}
这个订正过的程序说明了一条普遍的原则:如果可能的话,移位长度应该是常量。如果移位长度紧盯着你不放,那么你让其值超过31,或者如果左操作数是long类型的,让其值超过63的可能性就会大大降低。当然,你并不可能总是可以使用常量的移位长度。当你必须使用一个非常量的移位长度时,请确保你的程序可以应付这种容易产生问题的情况,或者压根就不会碰到这种情况。
前面提到的移位操作符的行为还有另外一个令人震惊的结果。很多程序员都希望具有负的移位长度的右移操作符可以起到左移操作符的作用,反之亦然。但是情况并非如此。右移操作符总是起到右移的作用,而左移操作符也总是起到左移的作用。负的移位长度通过只保留低5位而剔除其他位的方式被转换成了正的移位长度——如果左操作数是long类型的,则保留低6位。因此,如果要将一个int数值左移,其移位长度为-1,那么移位的效果是它被左移了31位。
总之,移位长度是对32取余的,或者如果左操作数是long类型的,则对64取余。因此,使用任何移位操作符和移位长度,都不可能将一个数值的所有位全部移走。同时,我们也不可能用右移操作符来执行左移操作,反之亦然。如果可能的话,请使用常量的移位长度,如果移位长度不能设为常量,那么就要千万当心。
语言设计者可能应该考虑将移位长度限制在从0到以位为单位的类型尺寸的范围内,并且修改移位长度为类型尺寸时的语义,让其返回0。尽管这可以避免在本谜题中所展示的混乱情况,但是它可能会带来负面的执行结果,因为Java的移位操作符的语义正是许多处理器上的移位指令的语义。
谜题27:变幻莫测的i值的更多相关文章
- JAVA中计算两个日期时间的差值竟然也有这么多门道
上半年春招的时候,作为面试官,对于面试表现的不错的同学会要求其写一小段代码看看.题目很简单: 给定一个日期,然后计算下距离今天相差的天数. 本以为这么个问题就是用来活跃面试氛围的,但是结果却让人大跌眼 ...
- Java常见问题3:周期之谜
谜24 byte是有符号的.范围是-128 - 127. 而0x90是int类型. 比較的时候.不相等. 假设想让其相等,须要进行类型转换:(byte & 0xff) 或者 (byte)0x9 ...
- 分布式系统理论进阶 - Paxos
引言 <分布式系统理论基础 - 一致性.2PC和3PC>一文介绍了一致性.达成一致性需要面临的各种问题以及2PC.3PC模型,Paxos协议在节点宕机恢复.消息无序或丢失.网络分化的场景下 ...
- Python 【第六章】:Python操作 RabbitMQ、Redis、Memcache、SQLAlchemy
Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度 ...
- Java使用Fork/Join框架来并行执行任务
现代的计算机已经向多CPU方向发展,即使是普通的PC,甚至现在的智能手机.多核处理器已被广泛应用.在未来,处理器的核心数将会发展的越来越多. 虽然硬件上的多核CPU已经十分成熟,但是很多应用程序并未这 ...
- python走起之第十一话
Redis redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorte ...
- JVM之数据类型
1.概述 Java虚拟机的数据类型可分为两大类:原始类型(Primitive Types,也称为基本类型)和引用类型(Reference Types).Java虚拟机用不同的字节码指令来操作不同的数据 ...
- Memcached & Redis使用
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度.Memcached ...
- 基于SPSS的美国老年夏季运动会运动员数据分析
本文是课程训练的报告,部分图片由于格式原因并没有贴出,有兴趣者阅读完整报告者输入以下链接 http://files.cnblogs.com/files/liugl7/基于SPSS的老 ...
随机推荐
- AOJ.559 丢失的数字
丢失的数字 Time Limit: 1000 ms Memory Limit: 64 MB Total Submission: 1552 Submission Accepted: 273 Descri ...
- 继承spring的validator接口,实现对数据的校验
在org.springframework.validation这个包中提供了一些对数据校验的方法,其中Validator接口是其中的一个. 现在用Validator接口,完成对数据的校验. 第一步:先 ...
- 怎么让Intellj Idea 把数据库的表映射成hibernate的domain对象
步骤如下: 第一步:连接数据源: 点击:idea右边的database.如下图所示: 或者你依次点击:view-->Tool windows--->database 然后你将看在如下点击下 ...
- Virtualization solutions on Linux systems - KVM and VirtualBox
Introduction Virtualization packages are means for users to run various operating systems without &q ...
- Vijos 1232 核电站问题
核电站问题 描述 一个核电站有N个放核物质的坑,坑排列在一条直线上.如果连续M个坑中放入核物质,则会发生爆炸,于是,在某些坑中可能不放核物质. 现在,请你计算:对于给定的N和M,求不发生爆炸的放置核物 ...
- python升级3.6后 yum出错File "/usr/bin/yum", line 30 ^
问题描述: # yum provides ifconfig File "/usr/bin/yum", line 30 except KeyboardInterrupt, e: ^ ...
- zhudongfangyu.exe进程是360主动防御进程,用来监控电脑系统,防止电脑病毒出现并阻止病毒或木马的安全进程
zhudongfangyu.exe进程是360主动防御进程,用来监控电脑系统,防止电脑病毒出现并阻止病毒或木马的安全进程
- Django-随机验证码
Python生成随机验证码,需要使用PIL模块. 安装: 1 pip3 install pillow 基本使用 1. 创建图片 from PIL import Image img = Image.ne ...
- python基础===两个list合并成一个dict的方法
def Run(): list2 = [, , , , ]; list3 = ["a", "b", "c", "d",& ...
- Linux实现利用SSH远程登录服务器详解
Linux实现利用SSH远程登录服务器详解 http://www.111cn.net/sys/linux/55152.htm