Java中的位操作

1 机器码

要进行位操作,首先得了解数据以二进制保存的形式吧。这里我们只以定点数讲解,即原码、反码、补码的知识。浮点数的机器码比较复杂,一般不会考到浮点数的位操作。

这里我只强调几点:

  • 整数0的机器码是32位全为0;
  • 32位全为1的整数是-1;
  • 首位为0,其余31位为1的数就是 int 所能表示的最大正整数;
  • 符号位为1,其余位全为0的不是 -0 ,而是int所能表示的最小负整数;
  • 整数的机器码是以其补码形式表示的,所以整数的补码很直观,但是负数的可能就不那么直观了。
    public static void main(String[] args) {
        for (int i = 0; i < 9; i++) {
            System.out.printf("i = %d\n   机器码:%-6s ;变负数:%-6s ; 取反:%-6s\n", i, Integer.toBinaryString(i),
                    Integer.toBinaryString(-i), Integer.toBinaryString(~i));
        }
        String MAX_VALUE = Integer.toBinaryString(Integer.MAX_VALUE);
        String MIN_VALUE = Integer.toBinaryString(Integer.MIN_VALUE);
        System.out.printf("\nInteger.MAX_VALUE: %d ; 机器码为:%s ; 长度:%d\n", Integer.MAX_VALUE, MAX_VALUE,
                MAX_VALUE.length());
        System.out.printf("Integer.MIN_VALUE: %d ; 机器码为:%s ; 长度:%d\n", Integer.MIN_VALUE, MIN_VALUE,
                MIN_VALUE.length());
    }
i = 0
   机器码:0      ;变负数:0      ; 取反:11111111111111111111111111111111
i = 1
   机器码:1      ;变负数:11111111111111111111111111111111 ; 取反:11111111111111111111111111111110
i = 2
   机器码:10     ;变负数:11111111111111111111111111111110 ; 取反:11111111111111111111111111111101
i = 3
   机器码:11     ;变负数:11111111111111111111111111111101 ; 取反:11111111111111111111111111111100
i = 4
   机器码:100    ;变负数:11111111111111111111111111111100 ; 取反:11111111111111111111111111111011
i = 5
   机器码:101    ;变负数:11111111111111111111111111111011 ; 取反:11111111111111111111111111111010
i = 6
   机器码:110    ;变负数:11111111111111111111111111111010 ; 取反:11111111111111111111111111111001
i = 7
   机器码:111    ;变负数:11111111111111111111111111111001 ; 取反:11111111111111111111111111111000
i = 8
   机器码:1000   ;变负数:11111111111111111111111111111000 ; 取反:11111111111111111111111111110111

Integer.MAX_VALUE: 2147483647 ; 机器码为:1111111111111111111111111111111 ; 长度:31
Integer.MIN_VALUE: -2147483648 ; 机器码为:10000000000000000000000000000000 ; 长度:32

MAX_VALUE / MIN_VALUE

MAX_VALUE
值为 2^31 -1 的常量,它表示 int 类型能够表示的最大值。

MIN_VALUE
值为 -2^31 的常量,它表示 int 类型能够表示的最小值。

为什么是31位而不是32位呢?因为最高位是符号位。第一位bit的基是2^0,第二位bit的基是2^2,……,第31位的基是2^30。所以MAX_VALUE的值为 2^31 -1,这个减一是经常容易被忽略的。那为什么10000000000000000000000000000000可以表示最小值呢? 因为这是一个巧妙的约定。


        int t1 = Integer.MAX_VALUE;
        System.out.printf("Integer.MAX_VALUE is: %d; the bitString is: %s\n", t1, Integer.toBinaryString(t1));
        t1++;
        System.out.printf("Integer.MAX_VALUE++ is: %d; the bitString is: %s\n", t1, Integer.toBinaryString(t1));

        int t2 = Integer.MIN_VALUE;
        System.out.printf("Integer.MIN_VALUE is: %d; the bitString is: %s\n", t2, Integer.toBinaryString(t2));
        t2--;
        System.out.printf("Integer.MIN_VALUE-- is: %d; the bitString is: %s\n", t2, Integer.toBinaryString(t2));
Integer.MAX_VALUE is: 2147483647; the bitString is: 1111111111111111111111111111111
Integer.MAX_VALUE++ is: -2147483648; the bitString is: 10000000000000000000000000000000
Integer.MIN_VALUE is: -2147483648; the bitString is: 10000000000000000000000000000000
Integer.MIN_VALUE-- is: 2147483647; the bitString is: 1111111111111111111111111111111


Java运算符的优先级

这里写图片描述

这里我们着重关注一下位移运算(左移<<、右移>>、无符号右移>>)的优先级,它们的优先级甚至低于加和减,但高于位运算。



java中>>与>>>的区别

有符号右移运算符>>

用来将一个数的各二进制位全部右移若干位。例如:a = a>>2,使a的各二进制位右移两位,移到右端的低位被舍弃,最高位则移入原来高位的值。如:
a = 00110111,则a>>2=00001101
b=11010011,则b>>2 = 11110100
右移一位相当于除2 取商,而且用右移实现除法比除法运算速度要快。


无符号右移运算符>>>

用来将一个数的各二进制位无符号右移若干位,与运算符>>相同,移出的低位被舍弃,但不同的是最高位补0,如:
a = 00110111,则a>>>2 = 00001101
b=11010011,则 b>>>2 = 00110100



位运算实例

题目:

  • m 为正整数。
  • 将 n 的二进制码中的 i–j 位的bit位换成 m的二进制码。
  • i是低位 j是高位。
  • i和j的设置一定与m和n的情况相符,不会出现异常。

代码

    public static int updateBits(int n, int m, int i, int j) {
        System.out.printf("n: %s ; m: %s\n\n", Integer.toBinaryString(n), Integer.toBinaryString(m));
        System.out.println("---------- Build mask ----------");
        int full1 = ~0; // 全1

        // 低位有 j+1 个0, 高位全为1
        int left = full1 << j + 1;
        System.out.printf("The left of mask is: %s\n", Integer.toBinaryString(left));

        // 高位全为0,低位有i个1
        int right = full1 >>> (32 - i);
        System.out.printf("The right of mask is:    %s\n", Integer.toBinaryString(right));

        // Left和right进行按位或运算,就可以得到 i--j 位为0,其余位全为1的mask
        int mask = left | right;
        System.out.printf("The mask is: %s\n\n", Integer.toBinaryString(mask));

        // 用 mask 将 n 上 i--j 位清零
        int maskN = mask & n;
        System.out.printf("Mask n and result is:    %s\n", Integer.toBinaryString(maskN));

        // 将 m 右移 i 位,与清零后的n 或
        int insertRest = maskN | (m << i);
        System.out.printf("Insert result is:    %s\n", Integer.toBinaryString(insertRest));
        return insertRest;
    }

输出

n: 10000000000000000000000000000000 ; m: 10011

---------- Build mask ----------
The left of mask is:    11111111111111111111111110000000
The right of mask is:   11
The mask is:    11111111111111111111111110000011

Mask n and result is:   10000000000000000000000000000000
Insert result is:   10000000000000000000000001001100
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值