byte,即字节,由8位的二进制组成。在Java中,byte类型的数据是8位带符号的二进制数。
在计算机中,8位带符号二进制数的取值范围是[-128, 127]
,所以在Java中,byte类型的取值范围也是[-128, 127]
。
取值范围分析
为什么是-128到127
首先1字节8位,还要加上符号位,这个好理解
比如:
0000 0001 表示10进制 1
1000 0001 表示10进制 -1
但是上面的这个负数并不是计算机存在内存中的数据,存在内存中的数据是原码的补码,实际存的是:
1000 0001 原码
1111 1110 反码
1111 1111 补码 这个才是-1
那最大的补码是:
byte的最大正数就是 01111111(最高位必须是0),也就是 127
那最小的补码是:
首先是负数
1000 0000 (补码)-> 1111 1111(反码) -> 1000 0000(原码) 还原原码后 -128
1111 1111 (补码) 还原原码后 -1
由此我们可以看出来二进制从 00000000 到01111111到10000000到 11111111
即 十进制从 0 到 127 到 -128 到 -1。
int a = 0;
int b = 127;
int c = -128;
int d = -1;
System.out.println(String.format("%8s", Integer.toBinaryString(a & 0xFF)).replace(' ', '0'));
System.out.println(String.format("%8s", Integer.toBinaryString(b & 0xFF)).replace(' ', '0'));
System.out.println(String.format("%8s", Integer.toBinaryString(c & 0xFF)).replace(' ', '0'));
System.out.println(String.format("%8s", Integer.toBinaryString(d & 0xFF)).replace(' ', '0'));
输出
00000000
01111111
10000000
11111111
原码,反码,补码
注意:我们这里举列的原码和反码只是为了求负数的补码,在计算机中没有原码,反码的存在,只有补码。
一.原码
1.正数的原码就是它的本身
假设使用一个字节存储整数,整数10的原码是:0000 1010
2.负数用最高位是1表示负数
假设使用一个字节存储整数,整数-10的原码是:1000 1010
二.反码
1.正数的反码跟原码一样
假设使用一个字节存储整数,整数10的反码是:0000 1010
2.负数的反码是负数的原码按位取反(0变1,1变0),符号位不变
假设使用一个字节存储整数,整数-10的反码是:1111 0101
三.补码(再次强调,补码才是在计算机中的存储形式。)
1.正数的补码和原码一样
假设使用一个字节存储整数,整数10的补码是:0000 1010(第三次强调:这一串是10这个整数在计算机中存储形式)
2.负数的补码是负数的反码加1
假设使用一个字节存储整数,整数-10的补码是:1111 0110(第三次强调:这一串是-10这个整数在计算机中存储形式)
四.在计算机中,为什么不用原码和反码,而是用补码呢?
因为在使用原码,反码在计算时不准确,使用补码计算时才准确。
1.使用原码计算10-10
0000 1010 #(10的原码)
+ 1000 1010 #(-10的原码)
------------------------------------------------------------
1001 0100 #(结果为:-20,很显然按照原码计算答案是否定的。)
2.使用反码计算10-10
0000 1010 #(10的反码)
+ 1111 0101 #(-10的反码)
------------------------------------------------------------
1111 1111 #(计算的结果为反码,我们转换为原码的结果为:1000 0000,最终的结果为:-0,很显然按照反码计算答案也是否定的。)
3.使用补码计算10-10
0000 1010 # (10的补码)
+ 1111 0110 # (-10的补码)
------------------------------------------------------------
1 0000 0000 # (由于我们这里使用了的1个字节存储,因此只能存储8位,最高位(第九位)那个1没有地方存,就被丢弃了。因此,结果为:0)