所有数值都是2进制

软件开发者都知道 10 进制、16 进制、8 进制。 
比如数字 10 的各位进制形式表现如下。

十进制:10
八进制:012
十六进制:0x0a
二进制:1010

原码 反码 补码

我们已经知道了一个 int 型数值是 4 个字节。每个字节有 8 位。但对于一个 int 或者其它整数类型如 (long)的数值而言还要注意的是,它的最高位是符号位。

  • 最高位为0表示正数。
  • 最高位为1表示负数

原码 将一个数字转换成二进制就是这个数值的原码。

int a = 5; //原码  0000 0000 0000 0101
int b = -3; //原码 1000 0000 0000 0011

反码 
分两种情况:正数和负数

    • 正数 正数的反码就是原码。
    • 负数 负数的反码是在原码的基础上,符号位不变 其它位都取反。
5 的原码:0000 0000 0000 0101

-3 的原码:1000 0000 0000 0011
-3 的反码:1111 1111 1111 1100

补码 
仍然分正数和负数两种情况

    • 正数 正数的补码就是原码。
    • 负数 负数的补码在反码的基础上加1。
5 的补码:0000 0000 0000 0101

-3 的反码:1111 1111 1111 1100
-3 的补码: 1111 1111 1111 1101

计算机在进行数值运算的时候,是通过补码表示每个数值的。

比如

5 - 3 = 5 + ( -3 )
相当于 0000 0000 0000 0101 + 1111 1111 1111 1101
= 1 0000 0000 0000 0010

最后的结果是1 0000 0000 0000 0010 这样的二进制,由于 int 类型只有 4 byte,所以最高位产生了溢出,进位 1 被丢弃。结果就变成了 0010 也就是 2,5 - 3 = 2 没有毛病。

位运算符 &、|、~、^、>>、<<

位运算符包含与运算符、或运算符、取反运算符、异或运算符、左移运算符和右移运算符。在下面的内容中,我将会一一讲解。

需要注意的是,下面测试用的数据都是 int 类型,int 类型是 4 个字节长度,但是为了方便说明示例中用的数值我都用 1 个字节表示。希望不会给大家造成困扰。

& 与运算符

规则 与运算时,进行运算的两个数,从最低位到最高位,一一对应。如果某 bit 的两个数值对应的值都是 1,则结果值相应的 bit 就是 1,否则为 0.

0 & 0 = 0,

0 & 1 = 0,

1 & 1 = 1

3 & 5 = 1 这是因为

0000 0011

&

0000 0101

=

0000 0001

按照规则,将两个数值按照低位到高位一一对齐运算,因为只有第 0 位都为 1,所以计算结果为 1.

| 或运算符

规则 与运算时,进行运算的两个数,从最低位到最高位,一一对应。如果某 bit 的两个数值对应的值只要 1 个为 1,则结果值相应的 bit 就是 1,否则为 0。

0 | 0 = 0,

0 | 1 = 1,

1 | 1 = 1

3 | 5 = 7 这是因为

0000 0011

|

0000 0101

=

0000 0111

~ 取反运算符

规则 对操作数的每一位进行操作,1 变成 0,0 变成 1。

~5 =>  0000 0101   ~  => 1111 1010

^ 异或运算符

规则 两个操作数进行异或时,对于同一位上,如果数值相同则为 0,数值不同则为 1。

1 ^ 0 = 1,

1 ^ 1 = 0,

0 ^ 0 = 0;

3 ^ 5 = 6,这是因为

0000 0011

|

0000 0101

=

0000 0110

值得注意的是 3 ^ 5 = 6,而 6 ^ 5 = 3

0000 0110

|

0000 0101

=

0000 0011

针对这个特性,我们可以将异或运算作为一个简单的数据加密的形式。比如,将一个mp4文件所有数值与一个种子数值进行异或得到加密后的数据,解密的时候再将数据与种子数值进行异或一次就可以了。

所以说异或运算可以作为简单的加解密运算算法。

>> 右移运算符

规则 a >> b 将数值 a 的二进制数值从 0 位算起到第 b - 1 位,整体向右方向移动 b 位,符号位不变,高位空出来的位补数值 0。

5 >> 1 ===>  1000 0000 0000 0101 >> 1  = 1000 0000 0000 0010 = 2
7 >> 2 ===> 1000 0000 0000 0111 >> 2 = 1000 0000 0000 0001 = 1
9 >> 3 ===> 1000 0000 0000 1001 >> 3 = 1000 0000 0000 0001 = 1
11 >> 2 ===> 1000 0000 0000 1011 >> 2 = 1000 0000 0000 0010 = 2

大家发现什么规律没有?a >> b = a / ( 2 ^ b ) ,所以 5 >> 1= 5 / 2 = 2,11 >> 2 = 11 / 4 = 2。

<< 左移运算符

规则 a << b 将数值 a 的二进制数值从 0 位算起到第 b - 1 位,整体向左方向移动 b 位,符号位不变,低位空出来的位补数值 0。

5 << 1 ===>  1000 0000 0000 0101 << 1  = 1000 0000 0000 1010 = 10
7 << 2 ===> 1000 0000 0000 0111 << 2 = 1000 0000 0001 1100 = 28
9 << 3 ===> 1000 0000 0000 1001 << 3 = 1000 0000 0100 1000 = 72
11 << 2 ===> 1000 0000 0000 1011 << 2 = 1000 0000 0010 1100 = 44

很明显就可以看出 a << b = a * (2 ^ b)

综合上面两个可以看到,如果某个数值右移 n 位,就相当于拿这个数值去除以 2 的 n 次幂。如果某个数值左移 n 位,就相当于这个数值乘以 2 ^ n。

通俗易懂的 Java 位操作运算讲解的更多相关文章

  1. 可能是最通俗易懂的 Java 位操作运算讲解

    https://blog.csdn.net/briblue/article/details/70296326

  2. java大数运算(讲解)

    在算法竞赛或者面试中我们经常遇到大数问题,例如求一个很大的阶层,大数加法等等. 住在这种情况下我们用常规解法(使用long long或long long int)肯定是不行的, 而我们自己用c/c++ ...

  3. 最通俗易懂的 Java 11 新特性讲解

    大多数开发者还是沉浸在 Java 8 中,而 Java 14 将要在 2020 年 3 月 17 日发布了,而我还在写着 Java 11 的新特性.Java 11 是 Java 8 之后的第一个 LT ...

  4. Java位运算原理及使用讲解

    前言日常开发中位运算不是很常用,但是巧妙的使用位运算可以大量减少运行开销,优化算法.举个例子,翻转操作比较常见,比如初始值为1,操作一次变为0,再操作一次变为1.可能的做法是使用三木运算符,判断原始值 ...

  5. Java位操作全面总结

    转载: Java位操作全面总结 在计算机中所有数据都是以二进制的形式储存的.位运算其实就是直接对在内存中的二进制数据进行操作,因此处理数据的速度非常快.在实际编程中,如果能巧妙运用位操作,完全可以达到 ...

  6. Java位操作全面总结[ZZ]

    Java位操作全面总结 在计算机中所有数据都是以二进制的形式储存的.位运算其实就是直接对在内存中的二进制数据进行操作,因此处理数据的速度非常快.在实际编程中,如果能巧妙运用位操作,完全可以达到四两拨千 ...

  7. Java 位运算超全面总结

    1.原码.反码.补码 关于原码.反码.补码的相关知识作者不打算在这里长篇大论,相关知识已有别的大佬总结很好了,还请老铁自行 Google,不过有篇知乎回答是作者学编程以来见过对相关知识最通俗易懂,生动 ...

  8. Java 位运算2-LeetCode 201 Bitwise AND of Numbers Range

    在Java位运算总结-leetcode题目博文中总结了Java提供的按位运算操作符,今天又碰到LeetCode中一道按位操作的题目 Given a range [m, n] where 0 <= ...

  9. Java 位运算总结

    一.Java中支持的位运算 位与(&):二元运算符,两个为1时结果为1,否则为0 位或(|):二元运算符,两个其中有一个为1时结果就为1,否则为0 位异或(^):二元运算符,两个数同时为1或0 ...

随机推荐

  1. ThreadLocal 原理

    ThreadLocal是什么 ThreadLocal是一个本地线程副本变量工具类.主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用, ...

  2. C++的vector的使用方法

    vector c++的vector的使用方法,创建,初始化,插入,删除等. #include "ex_vector.h" #include <iostream> #in ...

  3. 数据结构C语言实现----图

    邻接表储存结构 /*邻接表的边*/ typedef struct ArcNode { int adjvex; struct ArcNode *next; }ArcNode; /*邻接表的结点*/ ty ...

  4. Developer 转型记:一个开发平台的“魔力”

    摘要:开发者该如何借助AI技术,探索可沉淀的落地应用?在这AI技术浪潮下,实现完美的应用创新?我们一起来听听他的故事…… 随着政策的加持.技术快速的迭代,人工智能热潮正在蔓延.2020年,AI落地大考 ...

  5. PHP array_diff_ukey() 函数

    实例 比较两个数组的键名(使用用户自定义函数比较键名),并返回差集: <?phpfunction myfunction($a,$b){if ($a===$b){return 0;}return ...

  6. PHP strcspn() 函数

    实例 输出在字符串 "Hello world!" 中找到字符 "w" 之前查找的字符数: <?php高佣联盟 www.cgewang.comecho st ...

  7. swift基础_ set get方法 理解

    swift中重写set get方法是这样的. 先定义一个变量,当调用set方法的时候,系统会有一个newValue, 将newValue赋值给我们定义的变量,然后从get方法返回去. swift中一般 ...

  8. IDEA-Translation最优秀的翻译插件

    IDEA最优秀的翻译插件 效果 特性 多翻译引擎 Google翻译 有道翻译 百度翻译 多语言互译 文档翻译 语音朗读 自动选词 自动单词拆分 单词本 使用 申请有道智云翻译服务(可选): 注册有道智 ...

  9. Ubuntu16.04忘记用户登录密码以及管理员密码,重置密码的解决方案

    1. 问题现象: 密码遗忘 2. 问题原因 问题原因,搞不懂,只是修改了/etc/shadow和/etc/sudoers这俩文件 3. 解决方案 在系统开机前常按shift键进入grub界面,如下: ...

  10. Java实现邮箱验证码

    前言 相比于java实现短信验证码,邮箱验证码就简单了许多,目前只是简单的利用java发送自定义内容至指定邮箱,等过几天再弄短信和邮箱验证码Web版本的.查询网上资料,得知相比于网易邮箱,QQ邮箱是最 ...