原码
将一个整数转换成二进制形式,就是其原码。例如short a=10
, a的原码就是 0000 0000 0000 1010
;更改a的值a=-10
,此时a的原码就是1000 0000 0000 1010
。
总结:原码就是一个整数本来的二进制形式
反码
正数和负数的反码不一样
正数的反码就是其原码(原码和反码相同);负数的反码是将原码除 符号位 以外的所有位(数值位)取反,把0变成1,1变成0。
例如short a=10
, a的原码和反码都是0000 0000 0000 1010
;
更改a的值a=-10
,此时a的原码就是1111 1111 1111 0101
。
补码
补码的正数和负数的也不一样。
对于正数,它的补码就是其原码(正数三码合一);负数的补码就是其反码加1。
例如 short a=10
, a 的原码、反码、补码都是 0000 0000 0000 1010
; 更改a的值a=-10
,此时a的补码就是 1111 1111 1111 0110
补码是在反码的基础上打了一个补丁,进行了一下修正,所以叫'补码'。
重点: 在计算机内存中,整数一律采用补码的形式来存储。这意味着当读取整数时还要采用逆向的转换,也就是将补码转换为原码
小结一下:
1、正数的原码、反码和补码都是其本身的二进制
2、负数的反码将原码除 符号位 以外的所有位(数值位)取反,把0变成1,1变成0。补码就是其反码加1。

看到这里是不是有疑问?反码和补码是用来干嘛的?
别急,且让我先做几道题。
假设6和20都是short
类型的,现在我们要计算 6-18的结果,根据运算规则,它等价于6+(-18)。
如果采用原码计算,那么运算过程为
6-18=6+(-18)
= [0000 0000 0000 0110](原) + [1000 0000 0001 0010](原)
= [1000 0000 0001 1000](原)
=-24
直接用原码表示整数,让符号位也参与运算,结果显然是不正确的。
于是又开始了探索,不断试错,后来设计出反码。下面来演示反码的运算过程。
6-18=6+(-18)
= [0000 0000 0000 0110](原) + [1000 0000 0001 0010](原)
= [0000 0000 0000 0110](反) + [1111 1111 1110 1101](反)
= [1111 1111 1111 0011](反)
= [1000 0000 0000 1100](原)
= -12
计算结果是不是就正确了?这里不妨再思考一下,如果用反码就解决了,那补码为什么还要被设计?什么场景下会需要用到补码?下面我们再来看个栗子。
18-6=18+(-6)
= [0000 0000 0000 0001 0010](反)+[1111 1111 1111 1001](反)
= [1 0000 0000 0000 1011](反)
= [0000 0000 0000 1011](反)
= [0000 0000 0000 1011](原)
= 11
最前面那个1在加法运算的过程中进位了,内存溢出被截掉了
真实结果不应该是12吗?怎么通过反码计算的结果是11???
6-18的结果正确,18-6的结果就相差1。是不是按照反码来计算,是不是小的数减去大的数不正确, 大的数减去小的数就不对了?
你们可以按照上面的例子算一下, 然后你们就能发现,大的数减去小的数结果始终相差1。
相差的这个1要进行纠正,但是又不能影响小的数减去大的数的结果,怎么办呢? 聪明的你现在脑海里应该已经想起了我们今天要讲的另外一个主角“补码”。
下面我们来演示一下补码的计算过程:
6-18=6+(18)
= [0000 0000 0000 0110](补) + [1111 1111 1110 1110](补)
= [1111 1111 1111 0100](补)
= [1111 1111 1111 0011](反)
= [1000 0000 0000 1100](原)
= -12
18-6=18+(-6)
= [0000 0000 0001 0010](补) + [1111 1111 1111 1010](补)
= [1 0000 0000 0000 1100](补)
= [0000 0000 0000 1100](补)
= [0000 0000 0000 1100](反)
= [0000 0000 0000 1100](原)
=12
惊不惊喜?意不意外?
采用补码的形式正好把相差的1纠正过来,也没有影响小的数减去大的数。




