bit(比特)&byte(字节)
bit
叫做位
或者比特
,在计算机中数据都是以0
和1
存储的,一个bit
就对应一位数字byte
叫做字节
,是比bit
更高位的计量单位
1byte = 8bits
java中的基本数据类型
catagory | bytes | bits | 范围($2^n$) |
---|---|---|---|
boolean | 1 | 8 | $(-2)^7$ ~ $2^7-1$ |
char | 2 | 16 | $(-2)^{15}$ ~ $2^{15}-1$ |
—- | —- | —- | —- |
byte | 1 | 8 | $(-2)^7$ ~ $2^7-1$ |
short | 2 | 16 | $(-2)^{15}$ ~ $2^{15}-1$ |
int | 4 | 32 | $(-2)^{31}$ ~ $2^{31}-1$ |
float | 4 | 32 | $(-2)^{31}$ ~ $2^{31}-1$ |
long | 8 | 64 | $(-2)^{63}$ ~ $2^{63}-1$ |
double | 8 | 64 | $(-2)^{63}$ ~ $2^{63}-1$ |
仔细观察可以发现除了较为特殊的boolean
和char
之外,其余的类型按占空间从小到大排列,占用控件为:
$2^8$ -> $2^{16}$ -> $2^{32}$ -> $2^{64}$
对于char
,在java中无论要表示哪种字符,一个char
一定占用2bytes
,因为在java中使用Unicode字符集
进行utf-16
可变长编码,而utf-16
形如:u\8D63
,可以看到一个utf-16
字符占用了4个十六进制数,所以一个char
只会占用2bytes
的空间
这也就解释了为什么一个emoji会占用掉2个char,因为一个utf-16
无法完整表示一个emoji表情
为什么1个byte是8bits缺只能表示$2^7$量级?
要弄懂这个问题就非常有必要研究一下计算机对数据的编码方式
原码,反码,补码共同导致了一个byte
的表示区间限制在$(-2)^7$ ~ $2^7-1$中
原码,反码,补码
为了方便电路逻辑运算,在计算机中只有加法而没有减法,为了实现减法则需要把人类认知的减法转换成计算机中的加法: 1-1 = 1+(-1)
因为符号的存在,所以需要在二进制位中特殊化一个bit作为符号标志位,一个bit只可能为0或者1,正好满足表示正负的需求
所以在计算机中,一个8bit数1
的原码会被表示成: 原 -> 000000001
,而-1
会被表示为原 -> 10000001
原码
所谓源码就是没有经过任何处理的原始编码:
以8bit数字1
和-1
举例:
1 | (1) -> 原码 -> 0 000 0001 |
反码
既然可以表示负数了,那么是不是意味着直接将1
和-1
的编码按位相加就能得到正确的结果呢?
其实不然:
1 | (1) -> 原码 -> 0 000 0001 |
心里一个大写的 WTF,这就意味着需要计算机进行额外的操作来规避正负数相加
产生的问题
但是留给逻辑电路的运算方法选择已经不多了,无非就是&& || !
和他们之间的组合,其中&&
和||
是二元运算符,一定会引入其他的操作数,这样以来结果会变得不可预知,所以剩下来的操作就只有!
了
对于二进制运算我们应该知道,一个n bits
二进制数·x
按位做!
运算的话,结果等于 $2^n-x$,也就是说一个8bits表示的有符号
数字-1
按位做!
运算结果为-126
,而-126-1
正好等于-127
(有符号8bits最大值),而继续套用上面的公式,对-127
做!
运算就能直接得到结果-0
,正数同理可以得到结果+0
到这一步就已经明朗了,如果能得到一个相对最大值互补的结果,对它进行!
操作就能得到正确的值,则对于1-1
的例子,不难发现对-1
做!
后与1
相加,再做!
就能得到正确的结果:
1 | (1) -> 原码 -> 1 000 0001 |
但源码和反码相加会导致类型的矛盾,所以约定:
正数的反码等于原码,负数的反码为源码除符号位取反
这样就变成了:
1 | (1) -> 反码 -> 1 000 0001 |
DONE !
补码
问题虽然解决了,但并不完美
不难发现,在计算过程中0
这个数存在两种表示+0
和-0
,数学老师跟我说过0
没有符号,这个解决方式显然不够完美
所以这个时候补码
就出现了,补码
就是在反码的基础上+1
,但正数的补码和原码相同:
1 | (1) -> 补码 -> 0 000 0001 |
经过这样的计算,最高位因进位被舍弃,原先的-0
就变成了-128
,这就是正区间会少一个数的原因
PERFECT DONE !