您的位置:首页 > 编程语言 > Java开发

java解惑之表达式之谜(谜题6)

2014-12-31 21:24 148 查看
谜题6:多重转型
当程序连续使用多个转型时,会发生什么呢?看下面示例代码:
public class Multicast{
public static void main(String[] args){
System.out.println((int)(char)(byte) -1);
}
}
转换的顺序是从开始的int数值转为byte,再转为char,最后又转回int。那么最后打印的结果会是原来的-1么?当执行程序后就会发现,打印的是65535。从第一次转换开始,数值从32位变窄为8位,再扩宽为16,最后又扩宽为32位,但结果却不是原来的数值,这是为什么呢?
我们对三个转型一次做解析:从int到byte的转型执行了一个窄化原生类型的转换,直接将除低8位之外的所有位全部砍掉(java使用了基于2的补码的二进制运算,因此int类型的数值-1的所有32位都是置位的)。这次转换后,数值仍旧是-1;在byte到char的转型中,因为byte是有符号类型,而char是无符号类型。这时,转型是扩宽的,所以数值是能正确转型的,但却不能用char来表示一个负的byte数值。因为,从byte到char的转换不是一个扩宽原生类型转换,而是一个扩宽并窄化原生类型的转换(即先从byte先转换成int,再从int转换成char)。对于这种转型,有一条简单的规则来对其进行描述:如果最初的数值类型是有符号的,那么就执行符号扩展;如果它是char,那么不管它将要被转换成什么类型,都执行零扩展。所以,当数值-1从byte转换成char时,会发生符号扩展。作为结果的char数值的16位就都被置位了,因此它等于2^16-1,即65535,最后打印出的数值也正是这个。
因此,如果你在将一个char数值c转型为一个宽度更宽的类型,并且不希望有符号扩展,那么清晰表达意图,可以考虑使用一个位掩码,即使它并不是必需的: int i = c & 0xffff;或者写一句注释来描述转型的行为。
如果你在将一个char数值转型为一个宽度更宽的整型,并且希望有符号扩展,那么就先将char转型为一个short,它与char具有同样的宽度,但是它是有符号的,并写好注释;
如果你在将一个byte数值b转型为一个char,并且不希望有符号扩展,那么必需使用一个位掩码来限制它,这是一种通用做法,不需要任何注释: char c = (char) (b & 0xff);
如果你在将一个byte数值转换为char,并且希望有符号扩展,也应该写一条注释来进行说明、
总的来说,如果你通过观察不能确定程序将要做什么,那么它做的就很可能不是你想要的。所以我们就应该把自己的意图表达清楚,来避免犯错。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: