今天在做数据验证的时候出现一个诡异的问题:例如,有一个字符串"今天在做数据验证的时候出现一个诡异的问",这个字符串按字符异或得出值为-32,把-32强转为char类型作为字符串的校验位进行传输,接收到以后-32对应的字符转换为int类型却是65504。虽然当时就找到解决方式,但还是没有弄明白。经过一个上午的调查,线把原因整理如下:
首先:我们知道java中char占位两个字节,short占位两个字节,int占位4个字节,long占位8个字节。
其次:我们需要了解,在计算机结构中整数是以补码的方式存储的,至于为什么这么存储这里就不说了;正整数的补码是其本身,负整数的补码是其2进制位除符号位以为的每一位取反,并加1。
第三:java中char类型是以无符号整数表示的。这是我偶然看到的,怪自己粗心。
下面我们看一看数据结构
-32对应的int存储结构为:11111111111111111111111111100000(4个字节32位)
强转为char类型存储结构为:1111111111100000(2个字节16位),可见强转后是截取了int类型的低16位。
接下来接收者在接收到以后取到校验字符,强转为int类型存储结构为:1111111111100000(2个字节16位)。这里是没有问题的,问题在于把这个值与重新计算的校验值比较就不对了,因为从char类型强转为int类型,java默认该值为一个无符号整形(虽然java里面没有这个概念)存储结构为00000000000000001111111111100000,这里就很清楚了,该值为65504。
事实上原因在于int与char之间存储结构的差异,若按字符异或完成后,把int转为char比较就不存在问题了。
强转有风险,使用需谨慎!