前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JAVA中有趣的位运算

JAVA中有趣的位运算

作者头像
acupt
发布2019-09-02 15:56:15
8200
发布2019-09-02 15:56:15
举报
文章被收录于专栏:一杯82年的JAVA一杯82年的JAVA

&, |, ^, ~ 这些符号什么意思?有什么妙用?一起来感受它们的神奇吧~

当我们看一些源码的时候,经常会看到诸如 &、|、^、~ 的符号,这些就是位运算符。

位运算是直接对一个整形的二进制位进行操作,效率上比起加减乘除高不少,因此常运用在对性能很敏感的场景。

& 与运算

在二进制格式下,将两个数的每一位(1或0)分别做与运算(1&1=1,其它=0),得到一个新的二进制数。

代码语言:javascript
复制
public class Bit {
    public static void main(String[] args) {
        /*
         *   十进制       二进制
         *     5        0 1 0 1    从最低位(右)开始比较,不足的为0
         *     与          与
         *    14        1 1 1 0
         *     =           =
         *     4        0 1 0 0
         */
        System.out.println(5 & 14);
    }
}
// 输出: 4

判断整数n是奇数还是偶数:

  • n & 1 = 0 偶数
  • n & 1 = 1 奇数

原理:二进制格式下,右边第一位是0则是偶数,反之为奇数,因此只需要和1进行与运算即可。

| 或运算

在二进制格式下,将两个数的每一位(1或0)分别做或运算(0|0=0,其它=1),得到一个新的二进制数。

代码语言:javascript
复制
public class Bit {
    public static void main(String[] args) {
        /*
         *   十进制      二进制
         *     2        0 1 0     从最低位(右)开始比较,不足的为0
         *     或         或
         *     4        1 0 0
         *     =          =
         *     6        1 1 0
         */
        System.out.println(2 | 4);
    }
}
// 输出: 6

在Linux系统中,文件权限管理用1、2、4分别表示执行x、写w、读r的权限。

可以看做一个三位的二进制数,每一位分别表示一种权限的开启与否(1开启,0关闭),通过或运算组合就得到了不同的权限组合。

所以最高权限就是7,即二进制的“111”,拥有读、写、执行全部权限。而777权限则是所属用户、组用户、其他用户都拥有最高权限。

基于这个思路,我们只需要一个int或者long型的数字就可以存储几十个布尔类型的属性值,在某些场景下很有用。

^ 异或运算

代码语言:javascript
复制
异或:相同为false,不同true

在二进制格式下,将两个数的每一位(1或0)分别做异或运算(0^0=0,1^1=0, 其它=1),得到一个新的二进制数。

代码语言:javascript
复制
public class Bit {

    public static void main(String[] args) {
        /*
         *   十进制      二进制
         *     2        0 1 0     从最低位(右)开始比较,不足的为0
         *    异或       异或
         *     6        1 1 0
         *     =          =
         *     4        1 0 0
         */
        System.out.println(2 ^ 6);
    }
}
// 输出: 4

异或有个有趣的特性,它的逆运算是它本身,即A^B=C,C^B=A。基于这个特点,可以做一个简单的加密,把B作为秘钥,原文A用秘钥B加密后进行传输或存储等,使用时再用秘钥B进行解密。

通过异或操作还能实现两个数的交换,不需要中间值。(简单测了下性能并没有很棒棒)

代码语言:javascript
复制
public class Bit {

    public static void main(String[] args) {
        int x = 2;// 010
        int y = 4;// 100
        x = x ^ y;// 110
        y = y ^ x;// 010
        x = x ^ y;// 100
        System.out.println("x = " + x);
        System.out.println("y = " + y);
    }
}

/* 输出:

x = 4
y = 2

*/

~ 非运算

在二进制格式下,将两个数的每一位(1或0)分别做非运算(~0=1,~1=0),得到一个新的二进制数。

代码语言:javascript
复制
public class Bit {

    public static void main(String[] args) {
        System.out.println(~1);
    }

}
// 输出: -2

1进行非运算后值成了负数,不只是1,只要是正数,取非后都是负数,因为对于有符号的整数,最高位(最左边)是用来表示正负的,最高位为0是正数,1是负数。

正数1非运算后从“00000000000000000000000000000001”变成了“11111111111111111111111111111110”。

二进制表示负数的情况,要转成十进制需要两个步骤:

  1. 逐位取反 -> 00000000000000000000000000000001(2进制)
  2. 加1 -> 00000000000000000000000000000010(2进制) -> 2(10进制)
  3. 加上负号 -> -2(10进制)

总结

通过位运算可以巧妙且高效地达到某些目的,但如果不是很有必要,并不建议使用,毕竟可读性不高,别人看起来太痛苦(想想在阅读源码时看到一堆位运算的心情)。

这次简单介绍了与、或、非、异或,下次再讲讲移位操作的实践。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 一杯82年的JAVA 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • & 与运算
  • | 或运算
  • ^ 异或运算
  • ~ 非运算
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档