Java比特位操作

欢迎关注今日头条号、微信公众号、知乎号:仰望夜空一万次

随意聊聊并记录从小城市到上海工作生活的所思所想。

不去记录,有些事情都好像没有发生过。

本文介绍Java中bit的操作,涉及到原码、反码、补码的概念。最后引入编程珠玑中的题目实战如何使用bit的方式存储数据。

首先复习下原码、反码、补码的概念,为后续负整数的内存显示格式理解打好基础。

原码、反码、补码

在java虚拟机中整数有byte、short、int、long四种整数,分别表示 8位、16位、32位、64位有符号整数,使用补码表示。

  • 原码

所谓原码就是符号位加上数字的二进制表示,int为例,第一位表示符号 (0正数 1负数)简单期间一个字节表示

+7的原码为: 00000111
-7的原码为: 10000111

对于原码来说,绝对值相等的正数和负数只有符号位不同。

  • 反码

一个数如果为正,则它的反码与原码相同;一个数如果为负,则符号位为1,(符号位不变化,其余位数取反)。

换言之 该数的绝对值取反(绝对值取反各位都取反)。

为了简单起见,我们用1个字节来表示一个整数:

+7的反码为:00000111
-7的反码为: 11111000
  • 补码

补码:一个数如果为正,则它的原码、反码、补码相同;一个数如果为负,补码为反码加1。

为了简单起见,我们用1个字节来表示一个整数:

+7的补码为: 00000111
-7的补码为: 11111001

正数:它的原码、反码、补码相同。
负数:反码符号位不变化,其余位数取反。补码符号位不变化其余各位原码取反加1。

对于byte类型的整数,对于负数的表示快速记忆方式

10000000 = -128 (-128 + 0)
10000001 = -127 (-128 + 1)
10000011 = -125 (-128 + 3)
10000111 = -121 (-128 + 7)

运算符

  • 有符号右移运算符">>"

该数对应的二进制码整体右移,左边的用原有标志位补充,右边超出的部分舍弃。

代码示例

import org.junit.Test;
import static org.junit.Assert.assertEquals;

public class BitUnitTest {

    @Test
    public void byteTypeTest() {
        byte i = 127; //byte 最大值
        byte j = -128;//byte 最小值

        //获得符号位bit的信息
        int signI = (i >> 7) & 1;
        int signJ = (j >> 7) & 1;

        StringBuffer sb1=new StringBuffer();
        //获得byte中每一位的bit信息
        for(int k=0;k<=7;k++){
            int m = (i >> k) & 1;
            sb1.append(m);
        }
        System.out.println(sb1.reverse());// 01111111


        StringBuffer sb2=new StringBuffer();
        for(int k=0;k<=7;k++){
            int n = (j >> k) & 1;
            sb2.append(n);
        }
        System.out.println(sb2.reverse());// 10000000

        //127 补码表示0111 1111,它的原码、反码、补码相同.当使用有符号右移运算符">>",右移7位后,得到127的符号位0
        assertEquals(0,signI);

        //-128 补码表示1000 0000,它的原码1000 0000、反码1111 1111、补码1000 0000.
        // 当使用有符号右移运算符">>",右移7位后,得到-128的符号位1
        assertEquals(1,signJ);
    }
}

编程珠玑第一章问题解决

图片

实现纲要

图片

Java代码实现方式

import java.util.Random;

/**
 * @author wang.baozhi
 * @since 2019/10/21 下午8:27
 */
/*
 * 使用bit方式存储大量int类型的数字
 */
public class BitTest{
    public static void main(String[] args){
        int totalCount = 100; //待排序数的数量
        //java中int占4字节,一个字节包含8个bit,每一个bit可以代表一个数.计算初始化多少个int
        int len = (totalCount - 1)/32 +1;
        int[] storageIntArray = new int[len]; //声明并初始化

        //初始化被存取的int数组
        int[] inputIntArray = new int[totalCount];
        //产生随机输入数据,数据是乱序的,可能重复
        Random rand = new Random();
        for(int i=0;i<totalCount;i++){
            int randomInt=rand.nextInt(totalCount);
            inputIntArray[i] = randomInt;
        }

        //将数据以bit方式存入int数组
        for(int i=0;i<totalCount;i++){
            set(storageIntArray,inputIntArray[i]);
        }

        //从小到大,输出存储的数字
        for(int i=0;i<totalCount;i++){
            if(read(storageIntArray,i)==1)
                System.out.print(i+" ");
        }
    }


    //将第index位置的int值进行bit操作
    public static void set(int[] num,int i){
           int index=i/32;//确定使用int数组中的下标
           int position=i%32;//确定一个int表示32位bit中的哪一位bit
           num[index] |= (1<<position);//将int值的position位置bit值设置为1
    }


    //读取第i位,判断是0/1
    public static  int read(int[] num,int i){
        int index=i/32;//确定使用int数组中的下标
        int position=i%32;//确定一个int表示32位bit中的哪一位bit
        int result=(num[index] >> position) & 1;//判断第index个int值得第position个bit值是否是1
        return result;
    }
}

输出结果(每次不同):

3 4 5 6 7 8 9 10 14 15 16 19 21 23 25 26 28 29 32 33 34 35 36 37 38 40 41 42 44 45 46 49 53 54 55 56 58 59 60 61 62 63 65 66 67 68 71 73 74 75 76 78 79 80 81 83 89 91 92 94 95 96 97 98 

如果将不重复的从0到99的int类型数字,放入4个int组成的int数组中,int数组存储情况?

答:
31-0存入第一个int,63-32存入第二个int,95-64存入第三个int,127-96存入第四个int。
前3个int值得每一位bit都是1,因为int是以补码表示,32位bit都是1的int表示为-1。
96-99这四个数字存储在第四个int值的从右到左的四位bit,int值为显示为15。
所以四个int值得表现为int[-1,-1,-1,15]。

打印int值为-1,在内存中每一位bit的存取情况

@Test
public void intTypeTest() {
    int i = -1;
    StringBuffer sb=new StringBuffer();
    for(int k=0;k<=31;k++){
        int n = (i >> k) & 1;
        sb.append(n);
    }
    System.out.println(sb.reverse());
    //int类型-1,每一位bit打印的结果为11111111111111111111111111111111
    }

参考

  • Primitive Data Types

https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

  • Two’s complement

https://en.wikipedia.org/wiki/Two%27s_complement

https://stackoverflow.com/questions/3621067/why-is-the-range-of-bytes-128-to-127-in-java

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值