前言

之前了解过位运算符,左移<<等于乘以2,右移>>等于除以2。但是我在看jdk源码的时候发现了一个>>>三个符号的,不明白这是什么意思,就去搜了一下,发现还挺多的知识点的,就整理了一下。

首先我们知道,我们编写的程序最终都是在计算机底层进行的,计算机底层也仅支持0、1两种符号。所以当时网上有个键盘只有0、1两个键,那才是大佬用的键盘。扯远了。。。

先来复习一下java的基本类型都占多少字节,占多少位(1字节等于8位):

类型

字节数

位数

大小范围

byte

1

8

-2^8^~2^8^-1

short

2

16

-2^16^~2^16^-1

int

4

32

-2^32^~2^32^-1

long

8

64

-2^64^~2^64^-1

float

4

double

8

char

2

16

一个char类型可以存储一个汉字

boolean

1

true or false

移位操作是把数据看作二进制数,然后将其向左或向右移动若干位的运算。在Java中,移位操作符包含三种:<<左移运算符,>>带符号右移运算符,>>>无符号右移运算符。这三种操作符都只能作用于long,int,short,byte这四种基本整形类型上和char类型上。其他类型如double都无法使用位运算符,大家可以在ide中自行试验一下。

在java中,第一位用来表示数字的正负,第一位为零时表示正数,第一位为1时表示负数。我们拿最简单的8位byte类型举例:0000 0000表示0,0111 1111这个表示最大值(2^8^-1),再进行加一后就变成了1000 0000这时就变成了最小值(-2^8^)。再加一后变成1000 0001这时的值为-127。也就是从0到最大值然后转为最小值,然后再从最小值向零靠近。

左移操作符<<

左移操作符<<是将数据转换为二进制后,向左移动若干位,高位丢弃,低位补零

首先我们可以利用java中的方法获取一个数的二进制:Integer.toBinaryString(int val)

然后我们看下面这个例子:

public static void main(String[] args) {int a = 10;System.out.println("左移前的二进制:"+Integer.toBinaryString(a));a <<= 2;System.out.println("左移后的二进制:"+Integer.toBinaryString(a));System.out.println("左移后的十进制:"+a);
}

首先定义一个数,值为10,打印它的二进制(1010),然后进行左移操作2位。打印移位后的结果和二进制。

左移前的二进制:1010
左移后的二进制:101000
左移后的十进制:40

可以看出,将原来的二进制向左移动了两位,后面进行了补零。40=10 2 2。所以一次左移等于将这个数扩大了两倍。再来看一个负数的左移:

int b = -8;
System.out.println("左移前的二进制:" + Integer.toBinaryString(b));
b <<= 2;
System.out.println("左移后的二进制:" + Integer.toBinaryString(b));
System.out.println("左移后的十进制:" + b);

我们定义了一个负数(-8),打印出它的二进制,进行左移2位,左移后打印它的二进制,再将10进制打印出来查看。

左移前的二进制:11111111111111111111111111111000
左移后的二进制:11111111111111111111111111100000
左移后的十进制:-32

可以明显的看出二进制向左移动了两位,前面的位置丢弃,后面的位置补零。转换为10进制也符合我们之前的运算:-32 = -8 2 2。

带符号右移操作符>>

刚才的左移中,它向左移动,高位进行了丢弃,低位进行补零。但是右移操作时有一个符号位,操作不当将造成答案与预期结果不同。

带符号右移就是在向右移动若干位,低位进行丢弃,高位按照符号位进行填补。对于正数做右移操作时,高位补充0;负数进行右移时,高位补充1

再来用例子证明一下:

public static void main(String[] args) {int a = 1024;System.out.println("a右移前的二进制:" + Integer.toBinaryString(a));a >>= 4;System.out.println("a右移后的二进制:" + Integer.toBinaryString(a));System.out.println("a右移后的十进制:"+a);int b = -70336;System.out.println("b右移前的二进制:" + Integer.toBinaryString(b));b >>= 4;System.out.println("b右移后的二进制:" + Integer.toBinaryString(b));System.out.println("b右移后的十进制:"+b);
}

定义了两个变量,a=1024,然后向右移动4位。b=-70336也向右移动4位。分别将它们的移动前后二进制和十进制打印出来查看。

a右移前的二进制:10000000000
a右移后的二进制:1000000
a右移后的十进制:64
b右移前的二进制:11111111111111101110110101000000
b右移后的二进制:11111111111111111110111011010100
b右移后的十进制:-4396

a原来的二进制向右移动后,低位被丢弃,高位补充符号位也就是0。b原来的二进制向右移动后,低位被丢弃,高位补充符号位1。这也符号我们之前的运算规律:1024 / 2^4^ =16 ;-70336/ 2^4^ = -4396。

无符号右移操作符>>>

刚才的带符号右移操作符,我们在向右移动时带着高位的符号,正数填充0,负数填充0。现在不带符号的右移操作符大体与右移操作符一致,只不过不再区分正负数,结果都是高位补零,低位丢弃。

再用例子来证明一下:

public static void main(String[] args) {int a = 1024;System.out.println("a右移前的二进制:" + Integer.toBinaryString(a));a >>>= 4;System.out.println("a右移后的二进制:" + Integer.toBinaryString(a));System.out.println("a右移后的十进制:"+a);int b = -70336;System.out.println("b右移前的二进制:" + Integer.toBinaryString(b));b >>>= 4;System.out.println("b右移后的二进制:" + Integer.toBinaryString(b));System.out.println("b右移后的十进制:"+b);
}

还是刚才带符号右移的例子:这次我们仅仅把操作符换成无符号的右移操作符。

按照定义,其实在正数时不会有变化,因为在带符号的右移中正数也是高位补零。只不过当值为负数时会有变化,让我们看一下输出是不是符合猜想。

a右移前的二进制:10000000000
a右移后的二进制:1000000
a右移后的十进制:64
b右移前的二进制:11111111111111101110110101000000
b右移后的二进制:1111111111111110111011010100
b右移后的十进制:268431060

确实正数没有变化,验证了我们的猜想。然后是负数,这次向右移动时高位进行了补零,低位丢弃。改变后的数值不再符合我们之前的规律。

在无符号右移中,当值为正数时,依然符合之前的规律移动一位相当于除以2。但是当值为负数时不再符合规律。

当移位的位数超过数值所占用的位数会怎么样?

这个问题很有意思,我们刚刚都仅仅移动了2位或者4位,如果我们超过了int的位数也就是32位后会怎么样?我们如果对一个正数左移32位,低位补零补充了32次就变成0了,就如同下面代码所写的一样,最终a的结果会是什么。会变成0吗?

public static void main(String[] args) {int a = 10;a <<= 32;System.out.println(a);
}

经过我们运行后发现a的结果最终没变还是10。我们如果改成左移33位,它的结果会变成20。那么它的运算规律会不会是当超过位数后仅仅移动对位数的余数呢?比如对int做操作,它实际是运算 位数%32次。

经过多次试验发现答案确实就是这个猜想,当对int类型处理时,右移x位的运算为x%32位。

对其他类型也是一样吗?

我们刚才都是用的int类型,那么对于byte,short,char,long都一样吗?

先看一下byte类型。

public static void main(String[] args) {byte b = -1;System.out.println("操作前:"+b);b >>>= 6;System.out.println("操作后:"+b);
}

定义了byte的值为-1,即1111 1111,然后无符号右移6位,高位补零,低位丢弃,那么应该变成0000 0011也就是是3。让我们运行一下这段代码看一下打印出来的信息是不是3呢?

操作前:-1
操作后:-1

运行结果与我们预期的结果不一致!

我们将它的二进制也一起打印出来看一下究竟:

public static void main(String[] args) {byte b = -1;System.out.println("操作前十进制:"+b);System.out.println("操作前二进制:"+Integer.toBinaryString(b));b >>>= 6;System.out.println("操作后二进制:"+Integer.toBinaryString(b));System.out.println("操作后十进制:"+b);
}

这时再看一下运行结果

操作前十进制:-1
操作前二进制:11111111111111111111111111111111
操作后二进制:11111111111111111111111111111111
操作后十进制:-1

原来,Java在对byte,short,char这三种类型进行移位操作前,会将其先转型为int类型,然后再进行位操作。由于我们有进行了重新赋值将其赋值为原来的byte类型,所以又进行了从intbyte的先下转型,也就是截断。我们对上面的例子进行一下修改可以更直观的发现运行过程:

public static void main(String[] args) {byte b = -1;System.out.println("操作前十进制:"+b);System.out.println("操作前二进制:"+Integer.toBinaryString(b));System.out.println("进行无符号右移6位后的十进制:"+(b>>>6));System.out.println("操作后二进制:"+Integer.toBinaryString(b>>>6));
}

在这里我没有使用=进行重新赋值,而是计算完成后直接打印十进制和二进制的结果。

操作前十进制:-1
操作前二进制:11111111111111111111111111111111
进行无符号右移6位后的十进制:67108863
操作后二进制:11111111111111111111111111

从打印结果中可以明显的看出是先转换为int类型,然后进行位运算,位运算结束后由于重新赋值所以进行的截断。

对于long类型,它是64位,不用先转换。

总结

移位符是Java中的基本操作符,实际支持的类型只有intlong。在对byte,short,char类型进行移位操作时,都会先将其转换为int类型再进行操作。左移<<操作符相当于乘以2。带符号右移操作符>>相当于除以2。在Java中使用位运算符会比乘*,除/运算符更高效一些。而无符号右移符>>>在移动时高位补零,低位丢弃,在正数时仍然相当于除以2,但是在负数时结果却是变大了(由负数变为正数)。

本文由博客一文多发平台 OpenWrite 发布!
博主邮箱:liunaijie1996@163.com,有问题可以邮箱交流。

64位 unsigned char_Java位运算符详解相关推荐

  1. sizeof是c语言的一种运算符,C语言位运算和sizeof运算符详解

    位运算和sizeof运算符 C语言中提供了一些运算符可以直接操作整数的位,称为位运算,因此位运算中的操作数都必须是整型的.位运算的效率是比较高的,而且位运算运用好的话会达到意想不到的效果.位运算主要有 ...

  2. Twitter-Snowflake,64位自增ID算法详解

    Twitter-Snowflake,64位自增ID算法详解 from: http://www.lanindex.com/twitter-snowflake%EF%BC%8C64%E4%BD%8D%E8 ...

  3. MySQL—运算符详解(算术、比较、逻辑、范围运算符与集合运算符 模糊查询 NULL值运算与null值判断 位运算符)

    MySQL--运算符详解 知识纲要 算术运算符 比较运算符 逻辑运算符 范围运算符与集合运算符 模糊查询 NULL值运算与null值判断 位运算符 1.算术运算符 加 减 乘 除 取余 div 也表示 ...

  4. Java 位运算符详解

    文章目录 Java 位运算符详解 前情提要: 一.简介 二.如何区分 &,|,^ 是逻辑运算符还是位运算符? 三.例子 按位与 & 按位或 | 按位异或 ^ 按位取反 ~ 左移 < ...

  5. mysql所支持的比较运算符_mysql比较运算符有哪些?Mysql比较运算符详解

    比较运算符可用于比较数字和字符串.今天发一篇Mysql比较运算符详解,希望对初学者有所帮助,虽然现在流行NoSQL,但是MYSQL还是很有用的,数字作为浮点值进行比较,字符串以不区为例进行比较,=运算 ...

  6. C++移位运算符详解

    C++移位运算符详解 移位运算符包括左移"<<"和右移">>" 左移运算符<<: 1.无符号 语法格式:需要移位的数字< ...

  7. 解释一下java的短路运算,Java短路运算符和非短路运算符详解

    Java短路运算符和非短路运算符详解 时间:2017-09-15     来源:互联网 你了解Java短路运算符和非短路运算符吗?短路运算符就是我们常用的"&&". ...

  8. C语言学习——运算符详解

    C语言学习--运算符详解 一.学习运算符 (1)运算对象的数目 C语言中,运算符的运算对象可以是一个,称单目运算符:运算对象也可以是两个,称双目运算符:运算对象还可以是三个,称三目运算符. (2)运算 ...

  9. python3运算符和表达式实验报告_对Python3 * 和 ** 运算符详解

    在 Python 中,* 和 ** 具有语法多义性,具体来说是有四类用法. 1. 算数运算 * 代表乘法 ** 代表乘方 >>> 2 * 5 10 >>> 2 ** ...

最新文章

  1. String比较.equals
  2. 成为DBA的10条规则
  3. OpenSAP网址收藏
  4. python数据类型及使用方法_python 基本数据类型及方法
  5. [ZJOI2007] 时态同步(拓扑序)
  6. kubernetes cpu限制参数说明
  7. php面试编程题_PHP程序员面试题(经典汇总,mysql为主)
  8. 【lucene】lucene 分词 以及自定义分词器
  9. Java学习路线(完整详细版)
  10. Codeforces Round #250 (Div. 1) D. The Child and Sequence 线段树 区间取摸
  11. Unity笔记——1.Unity3D脚本基础
  12. CSS 媒体类型 ,相应式布局使用
  13. Django model 设置数据库 字段 编码
  14. 【聚类算法】带你轻松搞懂K-means聚类(含代码以及详细解释)
  15. vue动态切换背景图片background
  16. 【NOIP2017】跳房子
  17. TCP/IP协议号和端口
  18. c语言*p1 什么意思,p1什么意思_p1,意思_词汇大全意思全集
  19. 四_【Java_程序逻辑控制】
  20. 我是这样克服拖延症的

热门文章

  1. [工具]-文件明文导出工具
  2. Linux shell字符串截取与拼接
  3. solidity编码规范
  4. win32线程学习总结(临界区,互斥体,事件,信号量)
  5. easy_Maze 梅津美治郎 寒假逆向生涯(16/100)
  6. 用angr解二进制题目1
  7. 【PHP】网络相关封装的函数
  8. 152. 城市游戏【单调栈】
  9. html实战例子: 点击图片超链接跳转
  10. 【PAT乙级】1052 卖个萌 (20 分)