详解Java如何利用位操作符创建位掩码

目录
  • 位掩码
    • 举个例子
    • 编码
    • 解码
  • 提取一个比特
    • 第一比特
    • 任意位置的位
  • 提取多个比特
  • 应用一个比特掩码
  • 总结

在本文中,我们来看看如何使用位操作符实现低级别的位掩码。我们将看到我们如何将一个单一的int变量作为一个单独的数据容器。

位掩码

位掩码允许我们在一个数字变量中存储多个值。我们不再把这个变量看作一个整数,而是把它的每一个比特当作一个独立的值。

因为一个比特可以等于 0 或 1,我们也可以把它看成是 false 或 true 。我们也可以把一组比特切开,把它们当作一个较小的数字变量甚至是一个String

举个例子

假设我们有一个最小的内存空间,并且需要在一个int变量中存储所有关于用户账户的信息。前八位(来自32个可用位)将存储boolean信息,如 "该账户是否激活?"或 "该账户是否溢价?"

至于剩下的24位,我们将把它们转换成三个字符,作为用户的标识符。

编码

我们的用户将有一个标识符 "AAA",他将有一个活跃的高级账户(存储在前两个比特)。在二进制表示中,它将看起来像。

String stringRepresentation = "01000001010000010100000100000011";

使用内置的Integer#parseUnsignedInt方法,可以很容易地将其编码为一个int变量。

int intRepresentation = Integer.parseUnsignedInt(stringRepresentation, 2);
assertEquals(intRepresentation, 1094795523);

解码

这个过程也可以用 Integer#toBinaryString 方法来反转。

String binaryString = Integer.toBinaryString(intRepresentation);
String stringRepresentation = padWithZeros(binaryString);
assertEquals(stringRepresentation, "01000001010000010100000100000011");

提取一个比特

第一比特

如果我们想检查我们账户变量的第一位,我们只需要使用顺位 and 运算符和数字 1 作为掩码。因为数字 1在二进制形式中只有第一位被设置为1,其余的都是0,它将从我们的变量中删除所有的位,只留下第一个完整的位。

10000010100000101000001000000011
00000000000000000000000000000001
-------------------------------- &
00000000000000000000000000000001

然后我们需要检查产生的值是否不等于零。

intRepresentation & 1 != 0

任意位置的位

如果我们想检查其他的位,我们需要创建一个适当的掩码,这个掩码需要在给定的位置上有一个位设置为1,其余的设置为0。最简单的方法是对我们已有的掩码进行移位。

1 << (position - 1)

上面这行代码的位置变量设置为3,将把我们的掩码从 00000000000000000000000000000001 变成

00000000000000000000000000000100

因此,现在,比特方程将看起来像这样。

10000010100000101000001000000011
00000000000000000000000000000100
-------------------------------- &
00000000000000000000000000000000

把所有这些放在一起,我们可以写一个方法来提取给定位置上的单个比特。

private boolean extractValueAtPosition(int intRepresentation, int position) {
    return ((intRepresentation) & (1 << (position - 1))) != 0;
}

为了达到同样的效果,我们也可以将intRepresentation变量向相反方向移动,而不是改变掩码。

提取多个比特

我们可以用类似的方法从一个整数中提取多个比特。让我们提取我们的用户帐户变量的最后三个字节,并将其转换为一个字符串。首先,我们需要通过将变量向右移动来摆脱前八位的影响。

int lastThreeBites = intRepresentation >> 8;
String stringRepresentation = getStringRepresentation(lastThreeBites);
assertEquals(stringRepresentation, "00000000010000010100000101000001");

我们仍然有32位,因为int总是有32位。然而,现在我们只对前24位感兴趣,其余的都是零,会很容易被忽略。我们创建的int变量可以很容易地用作整数ID,但是因为我们想有一个字符串ID,所以我们还有一个步骤要做。

我们将把二进制的字符串表示法分成8个字符的组,把它们解析成char变量,然后把它们连接成一个最终的String

为了方便起见,我们还将忽略空字节。

Arrays.stream(stringRepresentation.split("(?<=\\G.{8})"))
  .filter(eightBits -> !eightBits.equals("00000000"))
  .map(eightBits -> (char)Integer.parseInt(eightBits, 2))
  .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
  .toString();

应用一个比特掩码

我们也可以创建一个掩码来同时检查许多位,而不是提取和检查单个位的值。我们想检查我们的用户是否有一个活跃的高级账户,所以他的变量的前两个比特都设置为1。

我们可以用以前的方法分别检查它们,但创建一个掩码来选择它们,会更快。

int user = Integer.parseUnsignedInt("00000000010000010100000101000001", 2);
int mask = Integer.parseUnsignedInt("00000000000000000000000000000011", 2);
int masked = user & mask;

因为我们的用户有一个活跃的账户,但它不是高级账户,所以被屏蔽的值将只有第一个比特被设置为1。

assertEquals(getStringRepresentation(masked), "00000000000000000000000000000001");

现在,我们可以轻松而廉价地断言一个用户是否符合我们的条件。

assertFalse((user & mask) == mask);

总结

在本教程中,我们学习了如何使用位运算符来创建位掩码,并应用它们来从整数中提取二进制信息。

到此这篇关于详解Java如何利用位操作符创建位掩码的文章就介绍到这了,更多相关Java位操作符创建位掩码内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java位掩码控制权限与(&)或(|)非(~)、>的介绍

    1. java 位掩码 java 位掩码,在java开发中很少有场景会用到掩码,但是当系统中需要判断某个对象是否有 某些权限时,可以通过位掩码来做. 位掩码 主要通过位运算,例如与(&).非(~).或(|).异或(^).移位(<<和>>)等来实现 权限判断功能. 1.1 简单介绍一下位运算符(计算均为二进制计算) << : 左移运算符,num << 1,相当于num乘以2 >> : 右移运算符,num >> 1,相当于num除

  • 详解Java的按位操作符

    Java的位操作符用来操作整数基本数据类型中的单个"比特"(bit),即代进制位.而我们知道比特就是0和1,那么,位操作就是对这些数据进行基本的操作.如果基本类型是char.byte或者short类型的数值进行移位处理,那么会转化成int类型,再进行移位的处理 Java的按位操作符 按位操作符会对两个参数对应的位执行布尔代数运算,并最终生成一个结果.这个操作符有与(&).非(~).或(|).异或(^).我们知道单位"比特"(bit),即代进制位,都是0和1,

  • 详解Java的位操作符

    Java的位操作符用来操作整数基本数据类型中的单个"比特"(bit),即代进制位.而我们知道比特就是0和1,那么,位操作就是对这些数据进行基本的操作.如果基本类型是char.byte或者short类型的数值进行移位处理,那么会转化成int类型,再进行移位的处理 Java的按位操作符 按位操作符会对两个参数对应的位执行布尔代数运算,并最终生成一个结果.这个操作符有与(&).非(~).或(|).异或(^).我们知道单位"比特"(bit),即代进制位,都是0和1,

  • 详解Java如何利用位操作符创建位掩码

    目录 位掩码 举个例子 编码 解码 提取一个比特 第一比特 任意位置的位 提取多个比特 应用一个比特掩码 总结 在本文中,我们来看看如何使用位操作符实现低级别的位掩码.我们将看到我们如何将一个单一的int变量作为一个单独的数据容器. 位掩码 位掩码允许我们在一个数字变量中存储多个值.我们不再把这个变量看作一个整数,而是把它的每一个比特当作一个独立的值. 因为一个比特可以等于 0 或 1,我们也可以把它看成是 false 或 true .我们也可以把一组比特切开,把它们当作一个较小的数字变量甚至是

  • 详解Java如何利用数字描述更多的信息

    目录 一 . 前言 二 . 单数中描述信息 三. 宏观思路 总结 一 . 前言 这一篇来趣味性的探讨一下 , 如何通过更少的空间描述更多的信息 在数据库里面 ,通常我们会用数字的递进来描述状态等信息 , 但是如果想进行更复杂的操作 , 就有必要对二进制有一定理解了. 二 . 单数中描述信息 单数中保存多个信息的意思是 : 我们能把多少信息存储到一串数字里面. 这里直接来通过一些案例来说明用法 用单个数字来表示状态 这也是业务中最常见的一种使用方式 , 通过数字 1,2,3 等来描述一个状态 ,

  • 详解Java是如何通过接口来创建代理并进行http请求

    场景 现在想要做这么一个事情,公司的dubbo服务都是内网的,但是提供了一个对外的出口,通过链接就能请求到对应的dubbo服务.(具体怎么做的应该就是个网关,然后将http请求转为dubbo请求,通过泛化调用去进行调用.代码看不到.)现在为了方便测试,我需要将配置的接口,通过http请求去请求对应的链接. 分析 项目的思想其实跟mybatis-spring整合包的思想差不多,都是生成代理去执行接口方法. https://www.jb51.net/article/153378.htm 项目是个简单

  • 详解Java创建线程的五种常见方式

    目录 Java中如何创建线程呢? 1.显示继承Thread,重写run来指定现成的执行代码. 2.匿名内部类继承Thread,重写run来执行线程执行的代码. 3.显示实现Runnable接口,重写run方法. 4.匿名内部类实现Runnable接口,重写run方法 5.通过lambda表达式来描述线程执行的代码 [面试题]:Thread的run和start之间的区别? Thread类的具体用法 Thread类常见的一些属性 中断一个线程 1.方法一:让线程run完 2.方法二:调用interr

  • 详解Java中的八种单例创建方式

    目录 定义 使用场景 单例模式八种方式 饿汉式(静态常量) 饿汉式(静态代码块) 懒汉式(线程不安全) 懒汉式(同步方法) 懒汉式(同步代码块) 双重检查锁方式 静态内部类方式 枚举方式 总结 定义 单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法) 使用场景 对于一些需要频繁创建销毁的对象 重量级的对象 经常使用到的对象 工具类对象 数据源 session 单例模式八种方式 饿汉式(静态常量) 代码 /**

  • 详解linux下利用crontab创建定时任务

    Linux下可以利用crontab创建定时任务. 常用搭配 crontab -e 编辑任务 crontab -l 查看所有任务[该用户] crontab -r 取消所有任务[该用户] 任务格式 × × × × × +命令(具体任务) 前5个参数表示时间,依次为: 参数 范围 分钟 0-59 小时 0-23 日期 1-31 月份 1-12 星期 0-6(0代表星期日) 特殊符号 为了精确表示定时,需要一些特殊符号来描述具体的任务执行时间.有以下几个符号: "/" 代表每,每隔多长时间 &

  • 详解Java对象创建的过程及内存布局

    一.对象的内存布局 对象头 对象头主要保存对象自身的运行时数据和用于指定该对象属于哪个类的类型指针. 实例数据 保存对象的有效数据,例如对象的字段信息,其中包括从父类继承下来的. 对齐填充 对齐填充不是必须存在的,没有特别的含义,只起到一个占位符的作用. 二.对象的创建过程 实例化一个类的对象的过程是一个典型的递归过程. 在准备实例化一个类的对象前,首先准备实例化该类的父类,如果该类的父类还有父类,那么准备实例化该类的父类的父类,依次递归直到递归到Object类. 此时,首先实例化Object类

  • 详解Java线程的创建及休眠

    一.进程vs线程 1.进程是系统分配资源的最小单位:线程是系统调度的最小单位 2.一个进程中至少要包含一个线程 3.线程必须要依附于继承,线程是进程实质工作的一个最小单位 二.线程的创建方式 继承Thread类 实现线程的创建(2种写法) 1种写法 public class ThreadDemo03 { static class MyThread extends Thread{ @Override public void run(){ System.out.println("线程名称:"

随机推荐