近日需要一个将字节数组转换为十六进制字符串输出的函数,于是开始编码如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
运行测试,一旦遇到负数总出现未可预料的结果,如参数为{-125,125,115,89}时运行结果为FFFFFF837D7359。
开始从网上查资料做修改,对byte数据进行与运算&oxff再进行转换,很抓狂到底为什么,再一顿搜索,原来问题出在java整数表示方法及位扩张问题上,在java中使用补码对整数进行表示。修改后代码如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
对于此问题找到了比较全面的解释如下:
转载自http://my.oschina.net/joymufeng/blog/139952
下面这行代码的输出是什么?
- 1
- 2
- 3
下面两行代码的输出相同吗?
- 1
- 2
- 3
- 4
- 5
请尝试在Eclipse中运行上面的两个代码片段,如果你对输出结果感到很惊讶,请继续往下读…
正如你所看到的:
第1个代码片段的运行结果是:-1
第2个代码片段的运行结果是:65535和255
上面的两个代码片段来源于《Java解惑》的第6个小问题“多重转型”,原题目内容如下:
- 1
- 2
- 3
- 4
- 5
上面的代码中连续进行了3次类型转换,最后的结果会回到-1吗?答案当然是不会,它输出的结果是65535。下面我为大家整理了相关的基础知识,相信大家读完后应该就知道其中的原因了。
一、Java中如何编码负数?
- 1
- 2
二、什么是符号扩展(Sign Extension)?
- 1
- 2
- 3
- 4
三、Java类型转换规则
-
Java中整型字面量
Java中int型字面量的书写方式有以下几种:
-
十进制方式,直接书写十进制数字
-
八进制方式,格式以0打头,例如012表示十进制10
-
十六进制方式,格式为0x打头,例如0xff表示十进制255
需要注意的是,在Java中012和0xff返回的都是int型数据,即长度是32位。
-
-
Java的数值类型转换规则
这个规则是《Java解惑》总结的:如果最初的数值类型是有符号的,那么就执行符号扩展;如果是char类型,那么不管它要被转换成什么类型,都执行零扩展。还有另外一条规则也需要记住,如果目标类型的长度小于源类型的长度,则直接截取目标类型的长度。例如将int型转换成byte型,直接截取int型的右边8位。
四、解析“多重转型”问题
连续三次类型转换的表达式如下:
- 1
-
int(32位) -> byte(8位)
-1是int型的字面量,根据“2的补码”编码规则,编码结果为0xffffffff,即32位全部置1.转换成byte类型时,直接截取最后8位,所以byte结果为0xff,对应的十进制值是-1.
-
byte(8位) -> char(16位)
由于byte是有符号类型,所以在转换成char型(16位)时需要进行符号扩展,即在0xff左边连续补上8个1(1是0xff的符号位),结果是0xffff。由于char是无符号类型,所以0xffff表示的十进制数是65535。
-
char(16位) -> int(32位)
由于char是无符号类型,转换成int型时进行零扩展,即在0xffff左边连续补上16个0,结果是0x0000ffff,对应的十进制数是65535。
五、几个转型的例子
在进行类型转换时,一定要了解表达式的含义,不能光靠感觉。最好的方法是将你的意图明确表达出来。
在将一个char型数值c转型为一个宽度更宽的类型时,并且不希望有符号扩展,可以如下编码:
- 1
上文曾提到过,0xffff是int型字面量,所以在进行&操作之前,编译器会自动将c转型成int型,即在c的二进制编码前添加16个0,然后再和0xffff进行&操作,所表达的意图是强制将前16置0,后16位保持不变。虽然这个操作不是必须的,但是明确表达了不进行符号扩展的意图。
如果需要符号扩展,则可以如下编码:
- 1
首先将c转换成short类型,它和char是 等宽度的,并且是有符号类型,再将short类型转换成int类型时,会自动进行符号扩展,即如果short为负数,则在左边补上16个1,否则补上16个0.
如果在将一个byte数值b转型为一个char时,并且不希望有符号扩展,那么必须使用一个位掩码来限制它:
- 1
(b & 0xff)的结果是32位的int类型,前24被强制置0,后8位保持不变,然后转换成char型时,直接截取后16位。这样不管b是正数还是负数,转换成char时,都相当于是在左边补上8个0,即进行零扩展而不是符号扩展。
如果需要符号扩展,则编码如下:
- 1
此时为了明确表达需要符号扩展的意图,注释是必须的。
六、小结
- 1
- 2
七、参考引用
-
阮一峰-关于2的补码
http://www.ruanyifeng.com/blog/2009/08/twos_complement.html -
wikipedia-Sign extension
http://en.wikipedia.org/wiki/Sign_extension -
Joshua Bloch, 陈昊鹏译 - 《Java解惑》
转载至:http://blog.csdn.net/leonwang_fly/article/details/47422235