无
分类: Java
2007-01-21 11:59:18
下面的程序是对两个十六进制(hex)字面常量进行相加,然后打印出十六进制的结果。这个程序会打印出什么呢?
public class JoyOfHex{
public static void main(String[] args){
System.out.println(
Long.toHexString(0x
}
}
看起来很明显,该程序应该打印出1cafebabe。毕竟,这确实就是十六进制数字10000000016与cafebabe16的和。该程序使用的是long型运算,它可以支持16位十六进制数,因此运算溢出是不可能的。
然而,如果你运行该程序,你就会发现它打印出来的是cafebabe,并没有任何前导的1。这个输出表示的是正确结果的低32位,但是不知何故,第33位丢失了。
看起来程序好像执行的是int型运算而不是long型运算,或者是忘了加第一个操作数。这里到底发生了什么呢?
十进制字面常量具有一个很好的属性,即所有的十进制字面常量都是正的,而十六进制或是八进制字面常量并不具备这个属性。要想书写一个负的十进制常量,可以使用一元取反操作符(-)连接一个十进制字面常量。以这种方式,你可以用十进制来书写任何int或long型的数值,不管它是正的还是负的,并且负的十进制常数可以很明确地用一个减号符号来标识。但是十六进制和八进制字面常量并不是这么回事,它们可以具有正的以及负的数值。如果十六进制和八进制字面常量的最高位被置位了,那么它们就是负数。在这个程序中,数字0xcafebabe是一个int常量,它的最高位被置位了,所以它是一个负数。它等于十进制数值-889275714。
该程序执行的这个加法是一种“混合类型的计算(mixed-type computation):左操作数是long类型的,而右操作数是int类型的。为了执行该计算,Java将int类型的数值用拓宽原始类型转换提升为一个long类型,然后对两个long类型数值相加。因为int是一个有符号的整数类型,所以这个转换执行的是符合扩展:它将负的int类型的数值提升为一个在数值上相等的long类型数值。
这个加法的右操作数0xcafebabe被提升为了long类型的数值0xffffffffcafebabeL。这个数值之后被加到了左操作数0x
1111111
0xffffffffcafebabeL
+ 0x
---------------------
0x00000000cafebabeL
订正该程序非常简单,只需用一个long十六进制字面常量来表示右操作数即可。这就可以避免了具有破坏力的符号扩展,并且程序也就可以打印出我们所期望的结果1cafebabe:
public class JoyOfHex{
public static void main(String[] args){
System.out.println(
Long.toHexString(0x
}
}