按位操作符

​ 按位操作符用来操作基本数据类型中的单个“比特”(bit),即二进制位。按位操作符会对两个参数中对应的位执行布尔代数运算,并最终生成一个结果。

​ 我们常用的按位操作符有以下几种:

  • &:与,如果参加运算的两个输入位都是1,则结果为1,否则生成一个输出位0

  • |:或,只要有一个输入位为1,则结果为1。换言之,只有两个输入位为0,结果才为0

  • ~:非,非运算符为一元运算符,只对一个操作符操作,也叫取反运算符

  • ^:异或,只有参加运算的两个输入数相反时,才会输出1

    我们做以下实验:

    1. public class Main {
    2. public static void main(String[] args) {
    3. int a = 16;
    4. int b = 15;
    5. String binaryStringA = Integer.toBinaryString(a);
    6. String binaryStringB = Integer.toBinaryString(b);
    7. // 填充到32位
    8. String a32 = StringUtils.leftPad(binaryStringA, 32,"0");
    9. String b32 = StringUtils.leftPad(binaryStringB, 32,"0");
    10. System.out.println(a+"的二进制为:"+a32);
    11. System.out.println(b+"的二进制为:"+b32);
    12. System.out.println("a&b="+(a&b));
    13. }
    14. }

    输出如下:

16的二进制为:00000000000000000000000000010000

15的二进制为:00000000000000000000000000001111

a&b=0


  1. **解释**:这里因为操作数都是int,所以我将其都填充到32,这样更直观,我们可以看到,转换成二进制后,1615每个bit上的值都是不一样的,所以最终的运算结果为0
  2. 上面我们测试了两个int类型的与操作,不知道大家有没有疑惑,如果参加运算的两个输入数类型不一致会怎么样呢?比如一个为int,另外一个为long呢?
  3. 我们来测试下:
  4. ```java

​ 结果如下:


我们可以得出结论:

当数据类型不一致时,会自动将低级的数据类型往高级转,在我们上面的例子中,很明显,a被转成了long类型。

我们也可以对编译生成的class文件进行反编译,可以看到如下的代码:

  1. public class Main {
  2. public Main() {
  3. }
  4. public static void main(String[] args) {
  5. int a = 16;
  6. long b = 9223372036854775807L;
  7. String binaryStringA = Integer.toBinaryString(a);
  8. String binaryStringB = Long.toBinaryString(b);
  9. String a32 = StringUtils.leftPad(binaryStringA, 32, "0");
  10. String b32 = StringUtils.leftPad(binaryStringB, 64, "0");
  11. System.out.println(a + "的二进制为:" + a32);
  12. System.out.println(b + "的二进制为:" + b32);
  13. System.out.println("a&b=" + ((long)a & b));
  14. }
  15. }

可以看到(long)a & b,在这里编译器自动进行了转换。

或跟异或在这里就不多赘述了,跟与操作差不多。

需要注意的是,非运算符,这是一个一元运算符,也就是说参与运算的只能有一个输入数,所以对于与,或,非,我们可以与赋值运算符“=”一起使用,但是非不行。比如我们可以写成a&=b或者a|=b,但是非是不行的另外对于布尔类型,不能执行非操作

移位操作符

​ 移位操作符操作的运算对象也是二进制的bit位。移位运算符只能用来处理整数类型(基本类型的一种)。左移运算符(<<)能按照操作符右侧指定的位数将操作符左边的数字向左移动(低位自动补0),对于右移这一操作,分为无符号右移(>>>)跟有符号右移(>>),所谓有符号右移是指,在进行运算时,如果原操作符的符号为正,则在高位补0,若为负,则在高位补1。而无符号右移,代表了不论正负,都会在高位补0。

​ 如果对char,byte,short类型的数值进行移位处理,那么在进行操作之前他们会被转成int类型,并且得到的结果也是一个int类型的值。到这里不知道大家会不会有一个疑惑,如果会被转成int类型的话,我们知道int类型的长度为32位(其中一位为符号位),那么如果移位的位数超过32怎么办呢?我们以a>>>n这个表达式为例,n代表移位的位数,实际上更准确的讲,移位的位数=n%32,即n除以32取余。

​ 测试代码如下:

  1. public class Main {
  2. public static void main(String[] args) {
  3. // 32%32=0,所以结果还是8
  4. System.out.println("8>>32=" + (8 >> 32));
  5. // 33%32=1,所以相当于右移一位,其实右移一位,就是除以2,左移一位就是乘以2
  6. // 以此类推,右移n位,相当于除以2的n次方
  7. // 左移n位,相当于乘以2的n次方(在数字没有溢出的前提下结论才成立)
  8. // 这个结论大家可以用画图的方式自己推导下
  9. System.out.println("8>>33=" + (8 >> 33));
  10. }
  11. }

移位操作符与“=”赋值运算符配合使用

在这里我们讨论下<<=,>>=,>>>=这几个运算符。

​ 主要讨论下面这种情况:我们知道对char,byte,short类型的数据进行移位运算时,会将其转换为int类型,那么在这种情况下,对一个byte类型的数据使用>>=,或者>>>=,会怎么样呢?主要就是讨论,如果运算后的结果超过了byte类型的上限怎么办呢?(这里只是以byte为例,对于其他两种类型也是一样的)

​ 测试代码:

  1. public class Main {
  2. public static void main(String[] args) {
  3. byte b = -1;
  4. System.out.println(Integer.toBinaryString(b));
  5. b >>>= 10;
  6. System.out.println(Integer.toBinaryString(b));
  7. System.out.println(Integer.toBinaryString(b>>>10));
  8. }
  9. }

​ 结果如下:

  1. 11111111111111111111111111111111
  2. 11111111111111111111111111111111
  3. (0000000000)1111111111111111111111

​ 这是因为,在运算过程中,byte类型会先转成int类型,但是当被赋值到一个byte上时,会被截断。在这种情况下就出现了这种诡异的情况(括号中的0是我手动补的)

​ 补充知识:

  1. 在计算机中,负数以原码的补码形式表达。
  2. 什么叫补码呢?这得从原码,反码说起。
  3. 原码:一个正数,按照绝对值大小转换成的二进制数;一个负数按照绝对值大小转换成的二进制数,然后最高位补1,称为原码。
  4. 比如 00000000 00000000 00000000 00000101 5 原码;10000000 00000000 00000000 00000101 -5 原码。  
  5. 反码:正数的反码与原码相同,负数的反码为对该数的原码除符号位外各位取反。
  6. 取反操作指:原为1,得0;原为0,得1。(10; 01
  7. 比如:正数00000000 00000000 00000000 00000101 的反码还是 00000000 00000000 00000000 00000101
  8. 负数10000000 00000000 00000000 00000101每一位取反(除符号位),得11111111 11111111 11111111 11111010
  9. 称:10000000 00000000 00000000 00000101 11111111 11111111 11111111 11111010互为反码。  
  10. 补码:正数的补码与原码相同,负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1.
  11. 比如:10000000 00000000 00000000 00000101 的反码是:11111111 11111111 11111111 11111010
  12. 那么,补码为:
  13. 11111111 11111111 11111111 11111010 + 1 = 11111111 11111111 11111111 11111011
  14. 所以,-5 在计算机中表达为:11111111 11111111 11111111 11111011

java基础篇 之 位运算符的更多相关文章

  1. Java基础——逻辑运算符、位运算符

    逻辑运算符.位运算符.三元运算符 逻辑运算符  public class Demon05 {     public static void main(String[] args) {          ...

  2. 第二十二节:Java语言基础-详细讲解位运算符与流程控制语句

    位运算符(二进制位运算) 运算符 运算 例子 << 左移 3 << 2 = 12 --> 3 * 2 * 2 =12 >> 右移 3 >> 1 = ...

  3. 小白—职场之Java基础篇

    java基础篇 java基础 目录 1.java是一种什么语言,jdk,jre,jvm三者的区别 2.java 1.5之后的三大版本 3.java跨平台及其原理 4.java 语言的特点 5.什么是字 ...

  4. java基础篇1

    JAVA基础篇1 注释 单行注释 //这是一个单行注释,由两个斜杠组成,不能嵌套多行注释 多行注释 /*这是一个 多行注释 ,//里面不能嵌套多行注释, 但是可以嵌套单行注释*/ 文档注释 /**ja ...

  5. 金三银四跳槽季,BAT美团滴滴java面试大纲(带答案版)之一:Java基础篇

    Java基础篇: 题记:本系列文章,会尽量模拟面试现场对话情景, 用口语而非书面语 ,采用问答形式来展现.另外每一个问题都附上“延伸”,这部分内容是帮助小伙伴们更深的理解一些底层细节的补充,在面试中可 ...

  6. java基础篇---HTTP协议

    java基础篇---HTTP协议   HTTP协议一直是自己的薄弱点,也没抽太多时间去看这方面的内容,今天兴致来了就在网上搜了下关于http协议,发现有园友写了一篇非常好的博文,博文地址:(http: ...

  7. Python基础篇(格式化输出,运算符,编码):

    Python基础篇(格式化输出,运算符,编码): 格式化输出: 格式:print ( " 内容%s" %(变量)) 字符类型: %s  替换字符串      %d 替换整体数字  ...

  8. SQL Server调优系列基础篇(联合运算符总结)

    前言 上两篇文章我们介绍了查看查询计划的方式,以及一些常用的连接运算符的优化技巧,本篇我们总结联合运算符的使用方式和优化技巧. 废话少说,直接进入本篇的主题. 技术准备 基于SQL Server200 ...

  9. java基础篇---I/O技术

    java基础篇---I/O技术   对于任何程序设计语言而言,输入输出(I/O)系统都是比较复杂的而且还是比较核心的.在java.io.包中提供了相关的API. java中流的概念划分 流的方向: 输 ...

随机推荐

  1. AJ学IOS 之控制器view显示中view的父子关系及controller的父子关系_解决屏幕旋转不能传递事件问题

    AJ分享,必须精品 一:效果 二:项目代码 这个Demo用的几个控制器分别画了不通的xib,随便拖拽了几个空间,主要是几个按钮的切换,主要代码展示下: // // NYViewController.m ...

  2. python脚本如何同时运行多个

    当我们想一次运行多个py脚本的时候你想到了什么应用场景了吗?当你想同时并行的处理一些对象时你有什么好方法吗?下面我就简单的总结一些这方面的小技巧,方便大家根据情况灵活处理. 1 用一个py脚本运行多个 ...

  3. golang slice 源码解读

    本文从源码角度学习 golang slice 的创建.扩容,深拷贝的实现. 内部数据结构 slice 仅有三个字段,其中array 是保存数据的部分,len 字段为长度,cap 为容量. type s ...

  4. Matlab学习-(4)

    1. 函数 1.1 原始方法 之前我调用函数的方法是,首先写好函数文件,然后保存,然后在主函数中调用.这种方法的不足在于会导致你的工作目录的文件太多,从而导致很乱.在网上找了一些解决方法. 1.2 本 ...

  5. Mysql使用终端操作数据库

      使用终端操作数据库       1.如何查看有什么数据库?     show databases;        2.如何选择数据库?    use databasesName;       3. ...

  6. [转载]绕过CDN查找真实IP方法总结

    前言 类似备忘录形式记录一下,这里结合了几篇绕过CDN寻找真实IP的文章,总结一下绕过CDN查找真实的IP的方法 介绍 CDN的全称是Content Delivery Network,即内容分发网络. ...

  7. [Java网络安全系列面试题] GET 和 POST 的区别在哪里?

    一. 概述 本文的内容源自其他博客的总结,属于笔者的读书笔记,结构如下: HTTP 的请求报文 GET 方法的特点 POST 方法的特点 GET 和 POST 的区别 二. HTTP 的请求报文 首先 ...

  8. 立体匹配-----NCC视差匹配

    目录 一.立体匹配算法 1.立体匹配算法分类 二.NCC 视差匹配方法 1.原理 2.NCC计算公式 3.算法流程 4.代码实现     5.不同场景运行 三.结论 四.遇到的问题及解决方法 一.立体 ...

  9. 关于foreach总是报错invalid param等问题

    原因为被foreach的数组可能为空,则会报错,只需做好容错即可,例如 if ( !empty( $arr ) ) { foreach ( $arr as $k => $v ) { } }

  10. Adobe Flash player 过期

    完美解决问题的办法,在百度中输入 "adobe flash player debugger",如图进入官网 选择对应操作系统的对应版本,下载安装,重启浏览器,一切ok IE内核浏览 ...