Java中的0与1

时间:2024-10-29 18:33:48

  我们都知道在计算机中,只有0与1的信号处理,任何值在计算机中都是以二进制表示的,而二进制整数都是以补码的形式存储的。在Java中,没有无符号数,最高位表示正负,0表示正数,1表示负数。

原码、反码和补码

原码:将整数直接化成二进制数。比如10D = 1010B (D表示十进制,B表示二进制)。十进制、二进制转化方式比较简单,这里不作讲解。这里1010即为原码,如果是byte型,占1字节,则原码为0000 1010 ,最高位是0,表示正数。

反码:正数的反码是原码。负数则是将其绝对值的原码按位取反,最高位为1。比如byte型的-10,先求得10的原码为0000 1010,则反码即1111 0101。

补码:正数补码和原码一样。负数则是将反码加1,比如byte类型的-10,求得其补码为1111 0101,则补码为1111 0110.

  用补码表示负数,这样能使得+0与-0是一样的,都是0000 0000(byte类型)。因为+0=0000 0000,而-0先求+0的反码1111 1111,再加1,为1 0000 0000,高位溢出舍去,则是0000 0000,和+0一样,所以这样0只有一种表示方式,唯一确定。同时这样使减法运算可以使用加法器实现,符合位也参与运算。比如10-10=10+(-10)。加减法是高频运算,使用同一个运算器,可以减少中间变量的存储开销,减少了运算器负担等等。

位移

左移:<<,将数值的二进制值左移n位,低位补0,比如2<<1,结果就是0010->0100,即将2左移1为变为了4。可以知道,左移的结果并不是乘2,比如0111 1111,左移1位后是1111 1110,是负数。负数左移也有可能是正数。注意:

 public static void main(String[] args) {
        byte a = Byte.MAX_VALUE;
        byte i = 1;
        System.out.println(a<<i); //输出254,并不是-2,
        int b = Integer.MAX_VALUE;
        System.out.println(b<<i); 
        //输出-2,这是因为Java中位移的结果是int/long型,byte型移位不会使高位改变值
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

右移:>>,将数值的二进制值右移n位,符号位参与移动,负数右移高位补1,其他补0。比如2>>1,结果就是0010->0001,(byte)-2>>1,结果就是1111 1110->1111 1111,变为了-1。
无符号右移:>>>,当向右移动时,正负数高位均补0,正数不断右移的最小值是0,负数不断右移的最小值是1。但为什么是这样呢?

  由上面例子知道位移运算作用于int型(32位)或long型(64位),并且int位移移动的位数是一个mod32的值,即20>>1与20>>33是一样的。long型则是mod64的值,即20>>1与20>>65一样。负数在>>>63位时,原最高位1移动到了最右边,左边全补0,达到最小值1,再移1位,即>>>64,则相当于>>>0,也就是本身。所以负数无符号右移最小值是1。正数无符号右移就是把有1的全移掉,变成最小值0。

其他位运算

按位取反(~)、按位与(&)、按位或(|)、按位异或(^)。但这里需要区分逻辑与(&&)、逻辑或(||)与之区别。
  &&和||只能用于boolean型的条件表达式,且具有短路功能,而位运算的&、|也可以用于数值,也能用于boolean型,比如true&false,因为boolean型底层也是用的0、1表示。

boolean a = (1>2)&&(2>3); //因为1>2是false,触发&&短路,不会比较后者
boolean a = (1>0)||(2>3); //因为1>0是true,触发||短路,不会判断后者
  • 1
  • 2