写在前面
本文的受众是计算机基础较为薄弱的童鞋,意在说明数字如何使用字节进行存储、转换。使用如果你的程序基础比较扎实,本文可能并不适合你。如果有不对或者不合适的地方,欢迎指正。
数字的表示
计算机本身只会进行逻辑计算,现有计算机每个 bit 位只能表示 0 和 1,可以理解成我们平时说的二进制。在使用二进制进行数值表示时,有以下三种基本方案:原码、反码、补码(关于三种概念之间的区别,请自行查阅)。
Java 中使用的是:补码,关于补码的解释,我这里更倾向于使用《CSAPP》(中文名:《深入理解计算机组成原理》)中的说法进行理解:
对于二进制:11111111(为方便计算,只算8位),从右至左依次为第 0 - 7 位,我们命名为 n,每一位表示的值大小为:2^n(2的 n 次方),最高位符号为负,因此这8位每位表示的大小为: 2^0、2^1、2^2、 2^3、2^4、2^5、2^6、-2^7(最高位符号为负)。
注意:因计算方法不同,-1 的二进制补码表示法是:11111111,不是 10000001,这一点请注意。
Java 中的类型转换
Java 中的类型转换,这里我们只关注部分数字之间的类型转换
byte -> int
对于大多数正数 byte 转换为 int 都是比较简单的,直接在二进制前面补 0 即可。
因为 Java 使用补码表示数字,因此当负数从 byte 类型转换为 int 类型时,为保证其数学逻辑正确性,前面需要补 1。
从数学逻辑上说:(byte) -1 在转换为 int 类型时,仍需要是 -1,所以当负数在进行从比较小范围的类型转为比较大类型数据时,前面补的应该是 1。 (byte) -1 = 0B11111111 转换为 int 后其二进制为:0B11111111_11111111_11111111_11111111
存储方式
在硬件层面,无论什么数据,都是以字节方式进行存储。对于数据的存储,主要有两种方式:大端表示法、小端表示法(更多说明请自行查阅)。一般情况下,计算机程序都是使用大端存储,而网络传输都是使用小端表示法。何为大端表示法,何为小端表示法?
对于任意一个 int 整形数字,我们可以将其分为 4 个字节,比如:对于整形数字:95467464,其十六进制表示为:0X05B0B7C8,其二进制为: 00000101_10110000_10110111_11001000,当我们需要将其使用 byte 存储至硬件中时,存储方式有两种,假设下列是内存中的某一段
从字节数组到 int(Java)
有了上述知识背景做铺垫,代码实现起来就简单的多,现在我们尝试从 byte 数组中恢复使用大端表示法存储的整型数字: