本文将介绍16进制转换到byte遇到的一些问题,其中会涉及计算机基础的补码的知识,如果不了解,可以先阅读我的另一篇关于补码的介绍:原码、反码、补码。
问题
我们先来看一道题
byte b = (byte) 0x1E;
int i = 0x1E;
System.out.println("b=" + b); // b=30
System.out.println("i=" + i); // i=30
16进制的0x1E转换成10进制,最后结果是30,没问题。
再看下面一道题。
byte b = (byte) 0xD8;
int i = 0xD8;
System.out.println("b=" + b); // b=-40
System.out.println("i=" + i); // i=216
奇怪,0xD8转换成十进制是216,那为什么用byte接收就变成-40了呢?
分析
用int接收0xD8,输出结果是正确的,用byte接收,结果就变成负数了,所以问题肯定是出在byte和int两种数据类型上,这两种类型有什么不同呢?
首先我们回忆下这两种数据类型的格式
1、计算机中最小的存储单位是bit(位);
2、1个byte = 8个bit;
3、1个int = 4个byte;
是不是因为0xD8超过了8位,导致1个byte存储不了呢?
0xD8=(0b) 1101 1000
0xD8的二进制数据没有超过8位啊,为什么还会出现负数呢?
在这里,还有一个知识点需要了解:计算机的数据都是以补码的形式存储计算的,正数的补码与原码相同,负数的补码是反码+1。
对于byte类型数据,一共只有8位,这里的最高位刚好是1,所以计算机认为这个是负数,所以要先求补码:符号位不变,数值位按位取反后+1
反码(1101 1000) + 1 -> 1010 0111 + 1 ->1010 1000
转换为十进制:-(2^5+2^3) = -40
至此,我们知道了这个-40的由来。
byte数据存储的数据范围就是从1000 0000到0111 1111(十进制表示为-128至127),所以如果当使用byte存储一个大于127的整数时,输出时就会变成负数。
如果没有负数,我们可以将负数位用来存储正数,这样byte可以就存储0至255的正数了。但计算机在计算时还是按照补码来计算的,这时,需要我们自己转换下,如果输出的十进制数小于0,就将该数加上模256,来得到它的正数。