1、有符号数和无符号数

其实就是正数和负数,最高位(第一位)是符号位,正数符号位为“0” ,负数符号位为“1” 。如 1和-1表示为如下
0000 0001
1000 0001

2、二进制的原码、反码、补码

原码

原码就是机器数,是加了一位符号位的二进制数(因为数值有正负之分)

如1和-1的原码表示为如下:
0000 0001
1000 0001

反码

带符号位的原码乘除运算时结果正确,而在加减运算的时候就出现了问题,比如: 用十进制表示:1 + (-1) = 0, 但用二进制表示:

00000001 + 10000001 = 10000010
将结果换算成十进制数也就是 -2。于是在原码的基础上发明了反码,用来解决这种问题。

如 1和-1反码表示为如下:
0000 0001
1111 1110

补码

虽然反码的出现解决了正负数的加减问题, 但却让0这个数字有了两种"形态": “0"和”-0",
但这是不合逻辑的,只应该有一个0,所以出现了补码。

正数的补码就是其本身
负数的补码是在其原码基础上, 符号位不变, 其余各位取反, 最后+1. (等同于在反码的基础上+1),如 1和-1反码表示为如下
0000 0001
1111 1111

小结

1、正数的原码、反码、补码都一样;
2、负数的反码 = 它的原码符号位不变,其他位取反(取反的意思:0 换成 1 、 1 换成 0 );
3、负数的补码 = 它的反码 +1;
4、0的反码、补码都是0;
【特别注意】
1、在计算机运算的时候,都是以 补码 的方式来运算的 。
2、二进制 转为 十进制,必须使用 二进制 的原码进行转换 。

举个栗子:

下面我们就使用“有符号数”来模拟一下,在计算机中是怎样运算的。

(1)正数相加:

例如:1+1 ,在计算机中运算如下:

1的原码为:

00000000 00000000 00000000 00000001

因为“正数的原码、反码、补码都一样”,所以,1的补码 = 1的原码,所以 1的补码+ 1的补码 就等于:

00000000 00000000 00000000 00000001
+
00000000 00000000 00000000 00000001

=

00000000 00000000 00000000 00000010

00000000 00000000 00000000 00000010( 转换为10进制) = 2

(2)正数相减:

例如:1 - 2,在计算机中运算如下:

在计算机中减运算其实是作为加运算来操作的,所以,1 - 2 = 1 + ( -2 )

第一步:把 1的补码找出来(因为正数的原码、反码、补码都一样,所以我们可通过原码直接获取补码):

1的补码:

00000000 00000000 00000000 00000001

第二步:把-2的原码找出来:

-2的原码:

10000000 00000000 00000000 00000010

第三步:把-2的反码找出来:

-2的反码:

11111111 11111111 11111111 11111101

第三步:把-2的补码找出来:

-2的补码:

11111111 11111111 11111111 11111110

第四步:1的补码与-2的补码相加:

00000000 00000000 00000000 00000001
+
11111111 11111111 11111111 11111110

=

11111111 11111111 11111111 11111111

第五步:将计算结果的补码转换为原码,反其道而行之即可(如果想将二进制转换为十进制,必须得到二进制的原码)

补码:11111111 11111111 11111111 11111111

=

反码:11111111 11111111 11111111 11111110

=

原码:10000000 00000000 00000000 00000001

第六步:将计算结果的二进制原码 转换 为十进制

二进制原码:10000000 00000000 00000000 00000001 = 1*2^0 = -1

3、思考:java中为什么byte的取值范围是-128~127

java中byte占一个字节, 也就是8bit(位), 其中最高位是符号位, 剩下7位用来表示数值.若符号位为0, 则表示为正数,范围为00000000~01111111(补码形式),也就是十进制的0-127. 若符号位为1, 则表示为负数, 范围为10000000~11111111(补码形式), -128~-1, 11111111转换为原码就是10000001,也就是-1。
在补码中,为了避免存在"-0",规定10000000为-128, 所以解释了byte的取值范围为什么是-128~127.

4、Java中的<< 和 >> 和 >>>

首先<< 和 >> 和 >>>是java中的位运算符,是针对二进制进行操作的。除了这些还有&、|、^、~、几个位操作符。不管是初始值是依照何种进制,都会换算成二进制进行位操作。这里主要讲解Java中的<< 和 >> 和 >>>。

<< 表示左移移,不分正负数,低位补0 

注:以下数据类型默认为byte为8位,左移时不管正负,低位补0

正数:r = 20 << 2

20的二进制补码:0001 0100

向左移动两位后:0101 0000

结果:r = 80

负数:r = -20 << 2

-20 的二进制原码 :1001 0100

-20 的二进制反码 :1110 1011

-20 的二进制补码 :1110 1100

左移两位后的补码:1011 0000

反码:1010 1111

原码:1101 0000

结果:r = -80

‘ >> ’表示右移,如果该数为正,则高位补0,若为负数,则高位补1;

注:以下数据类型默认为byte为8位

正数:r = 20 >> 2 

20的二进制补码:0001 0100

向右移动两位后:0000 0101

结果:r = 5

负数:r = -20 >> 2 

-20 的二进制原码 :1001 0100

-20 的二进制反码 :1110 1011

-20 的二进制补码 :1110 1100

右移两位后的补码:1111 1011

反码:1111 1010

原码:1000 0101

结果:r = -5

‘ >>> ’ 表示无符号右移,也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0 

注:以下数据类型默认为int 32位

正数: r = 20 >>> 2

的结果与 r = 20 >> 2 相同;

负数: r = -20 >>> 2

-20原码:10000000 00000000 00000000 00010100

反码:11111111 11111111 11111111 11101011

补码:11111111 11111111 11111111 11101100

右移:00111111 11111111 11111111 11111011

结果:r = 1073741819

最后,若有不足或者不正之处,欢迎指正批评,感激不尽!

欢迎各位关注我的公众号,里面有一些java学习资料和一大波java电子书籍,比如说周志明老师的深入java虚拟机、java编程思想、核心技术卷、大话设计模式、java并发编程实战…都是java的圣经,不说了快上Tomcat车,咋们走!最主要的是一起探讨技术,向往技术,追求技术,说好了来了就是盆友喔…

在这里插入图片描述

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐