众所周知,计算机底层是二进制。而java作为一门计算机编程语言,也对二进制的位运算提供了完整的支持。

在java中,int是32位的,也就是说可以用来实现32位的位运算。方便起见,我们一般用16进制对它赋值,比如: 0011表示成16进制是 0x3, 110111表示成16进制是 0x37。

那么什么是位运算呢?位运算是将数据看做二进制,进行位级别的操作。主要有移位运算和逻辑运算

移位运算:

  • 左移:操作符为<<,向左移动,右边的低位补0,左边高位舍弃,将二进制看做整数,左移1位就相当于乘以2。
  • 无符号右移:操作符为>>>,向右移动,右边的舍弃掉,左边补0。
  • 有符号右移:操作符为>>,向右移动,右边的舍弃掉,左边补的值取决于原来最高位,原来是1就补1,原来是0就补0,将二进制看做整数,右移1位相当于除以2。

例如:

int a = 4; //
a = a >> 2; // 001,等于1
a = a << 3 // 1000,变为8

逻辑运算有:

  • 按位与 &:两位都为1才为1
  • 按位或 |:只要有一位为1,就为1
  • 按位取反 ~: 1变为0,0变为1
  • 按位异或 ^ :相异为真,相同为假

例如:

int a = ...;
a = a & 0x1 // 返回0或1,就是a最右边一位的值。
a = a | 0x1 //不管a原来最右边一位是什么,都将设为1

我们来看几个简单的应用场景:

场景一:判断奇偶

分析:奇数都不是2的整数倍,转换成二进制后最低位必然为1,偶数则相反。利用这个特性我们可以很容易的通过位运算判断一个整数的奇偶性。

看代码:

    int i = 1;// 二进制存储方式为00000000000000000000000000000001
int j = 5;// 二进制存储方式为00000000000000000000000000000101
int k = 6;// 二进制存储方式为00000000000000000000000000000110
if ((i & j) == 1) {
System.out.println("j的最低位为1,为奇数");
}
if ((i & k) == 0) {
System.out.println("k的最低位为0,为偶数");
}

场景二:判断一个正整数是不是2的整数次幂

分析:我们先来看一下常见的2的整数次幂的数:2、4、8、16,转化成二进制依次为:10、100、1000、10000,发现规律了没有?那就是除了首位是1,其他全是0。恰巧这些数减去1后等于他们依次按位取反的结果,比如8-1=7,二进制是111,可以通过8的二进制1000按位取反得到。而8&7=0,提取一下规律就是:

(n&(n-1))==0

符合这个规律的n就是2的整数次幂了。

场景三:简单的集合处理

不废话,直接看代码:

public class SimpleSet {
public static final int A = 0x01;// 最后四位为0001
public static final int B = 0x02;// 最后四位为0010
public static final int C = 0x04;// 最后四位为0100
public static final int D = 0x08;// 最后四位为1000 private int set = 0x00;// 初始0000,空集合 public void add(int i) {// 将i对应位的值置为1,重复add不影响。默认传入值为ABCD之一,此处省去边界判断
set |= i;
} public boolean contain(int i) {// 判断相应位置是否为1
return (set & i) == i;
} public boolean remove(int i) {// 来不及不解释了快看代码
if (contain(i)) {
set -= i;
return true;
} else {
return false;
}
}
}

测试一下:

  public static void main(String[] args) {
SimpleSet set = new SimpleSet();
System.out.println(set.contain(A));
set.add(B);
System.out.println(set.contain(A));
System.out.println(set.contain(B));
set.add(A);
set.add(C);
System.out.println(set.contain(A));
set.remove(A);
System.out.println(set.contain(A));
System.out.println(set.remove(A));
System.out.println(set.contain(C));
}

输出为:

false
false
true
true
false
false
true

好的,没有问题。

大家可能会觉得,上面的示例代码中的A、B、C、D有点类似于枚举,事实上jdk源码中的关于枚举的集合类EnumSet使用的就是类似的方案,当然比这个复杂得多,有兴趣的可以去翻一下源码,这个方案它有个名字,叫位向量。

顺便提一句,java中int的包装类Integer里面有很多静态工具方提供位运算操作,且大都十分复杂,感兴趣的可以去看看

结语:

位运算是计算机最擅长的运算,jdk的源码中也大量地使用了它,搞明白它有助于我们更加深入的理解计算机,也有助于我们写出更优雅的代码。

Java中的位运算及简单的算法应用介绍的更多相关文章

  1. Java中的位运算

    昨天去面试的时候做到了一道Java的位运算题目,发现有个运算符不懂:">>>",今天特地查了一下,并小结一下常见的位运算符号: ~  按位非(NOT)(一元运算) ...

  2. Java中关于位运算的面试题

    位运算的效率是最高的,因为位位运算是直接对二进制进行操作 位运算只能应用于整型和char类型(char类型可以看做是特殊的无符号的整形) 面试题: a: 判断一个数是否是奇数 a & 1 == ...

  3. java中通过位运算实现多个状态的判断

    通过 <<  |  & ~ 位运算,实现同时拥有多个状态 通过 << 定义数据的状态 public interface LogConstants { /** * 消耗标 ...

  4. java中的位运算及移位运算

    为了方便对二进制位进行操作,Java给我们提供了以下四个二进制位操作符: &    按位与 |     按位或 ^    按位异或 ~    按位取反 Java中有三个移位运算符: 左移:&l ...

  5. Java二进制和位运算,这一万字准能喂饱你

    基础不牢,地动山摇.本文已被 https://www.yourbatman.cn 收录,里面一并有Spring技术栈.MyBatis.JVM.中间件等小而美的专栏供以免费学习.关注公众号[BAT的乌托 ...

  6. Java中的位掩码BitMask

    目录 JDK源码的使用 日常工作中的使用 JDK源码的使用 最近在JDK源码中闲逛,无意中看到了java.lang.reflect.Modifier这个类,这个类很简单,都是些常量定义和判断方法,于是 ...

  7. Java中的递归运算

    Java中的递归运算是一种在自己的方法内部调用自己的方法 递归的设计思想是:把一个复杂的问题,分解为若干个等同的子问题,重复执行,直到之问题能够简单到直接求解,这样复杂的问题就得以解决. 递归运算有两 ...

  8. (转)Java中使用正则表达式的一个简单例子及常用正则分享

    转自:http://www.jb51.net/article/67724.htm 这篇文章主要介绍了Java中使用正则表达式的一个简单例子及常用正则分享,本文用一个验证Email的例子讲解JAVA中如 ...

  9. java 中 “文件” 和 “流” 的简单分析

    java 中 FIle 和 流的简单分析 File类 简单File 常用方法 创建一个File 对象,检验文件是否存在,若不存在就创建,然后对File的类的这部分操作进行演示,如文件的名称.大小等 / ...

随机推荐

  1. Java多线程编程之读写锁【ReentrantReadWriteLock】

    有时候我们需要有这样的需求:        对于同一个文件进行读和写操作,普通的锁是互斥的,这样读的时候会加锁,只能单线程的读,我们希望多线程的进行读操作,并且读的时候不能进行写操作,写的时候不能进行 ...

  2. 通过Visual Studio快速生成Json或XML反序列化类代码

    Visual Studio不愧是宇宙第一强的IDE工具,在Json.XML格式漫天飞.反序列化需求遍地走的现在,居然到最近才知道原来微软已经在Visual Studio集成了这么一样的良心功能,自动根 ...

  3. [C#] 生成中文电子通讯录

    var template = @" BEGIN:VCARD VERSION:2.1 N;CHARSET=gb2312:;{0};;; FN;CHARSET=gb2312:{0} TEL;CE ...

  4. LVS简单理解

    LVS LVS(Linux Virtual Server)即Linux虚拟服务器 目前LVS已经被集成到Linux内核模块中.该项目在Linux内核中实现了基于IP的数据请求负载均衡调度方案 终端用户 ...

  5. python3基础之“函数(2)”

    1.def:定义一个函数 def f(x): return x+1 #返回函数值 a=f(2) print(a) >>3 def even_odd(x): if x%2==0: " ...

  6. 将H5页面打包成安卓原生app

    第一步:下载HBuilderX,新建项目选择5+App新建一个空项目如下图 新建后项目目录结构如下图 第二步,将你要打包成安卓app的文件打包,最后生成的文件目录如下图 1.打包完成后,将对应文件内容 ...

  7. 2.将多个元素设置为同一行?清除浮动有几种方式?【HTML】

    1.将多个元素设置为同一行:float,inline-block 清除浮动的方式: 方法一:添加新的元素 .应用 clear:both: 方法二:父级div定义 overflow: hidden: 方 ...

  8. WPF登录功能,对于密码框的操作,其实WPF有个PasswordBox专门的密码框控件,完全可以选择自己要显示的密码符号。

    在链接数据库后,点击登录时需要判断用户名和密码框是否为空,而PasswordBox不像textbox那样判断 textbox判断文本框为空 if (this.UserName.Text.Trim()= ...

  9. Apache Commons FileUpload实现文件上传

    一.Apache Commons-FileUpload简介 Apache Commons是一个专注于可重用Java组件的所有方面的 Apache 项目. Apache Commons项目由三个部分组成 ...

  10. SQL SERVER-SSMS安装联机丛书 book online

    1.下载地址:https://www.microsoft.com/en-us/download/details.aspx?id=42557 2.解压. 3.在SSMS中添加引用. 选择解压路径找到ms ...