- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
本文中所提到的运算都是基于整数来说的,因为只有整数(包括正数和负数)在操作系统中是以二进制的补码形式运算的,关于原码、反码、补码、位运算、移位运算的背景这里不再介绍,网上资料很多,感兴趣的可自行搜索。 java中能表示整数数据类型的有byte、short、char、int、long,在计算机中占用的空间使用字节描述,1个字节使用8位二进制表示.
数据类型 | 字节数 | 二进制位数 | 表示范围 | 默认值 |
---|---|---|---|---|
byte | 1 | 8 | -2^7 -- 2^7-1 | 0 |
char | 2 | 16 | 0 -- 2^16-1 | '\u0000' (代表字符为空 转成int就是0) |
short | 2 | 16 | -2^15 -- 2^15-1 | 0 |
int | 4 | 32 | -2^31 -- 2^31-1 | 0 |
long | 8 | 64 | -2^63 -- 2^63-1 | 0L |
使用位运算前需要先弄清楚这几个概念 。
原码也叫机器码,整数的二进制形式表示,最高位为符号位。1表示负数,0表示正数,除去符号位后剩余其他的所有位是该整数的绝对值的二进制值.
int a = 7; //原码二进制表示为:00000000 00000000 00000000 00000111
int b = -7;//原码二进制表示为:10000000 00000000 00000000 00000111
反码需要区分是正数还是负数,正数的反码跟原码相同,负数的反码是除符号位外,其他位取反(即负数的最高位是1不变,其他位0变成1,1变成0).
int a = 7; //反码二进制表示为:00000000 00000000 00000000 00000111
int b = -7;//反码二进制表示为:11111111 11111111 11111111 11111000
补码也需要区分是正数还是负数,正数的补码跟原码相同,负数的补码是反码最低位加1.
int a = 7; //补码二进制表示为:00000000 00000000 00000000 00000111
int b = -7;//补码二进制表示为:11111111 11111111 11111111 11111001
说完了概念,其实这里的原码是方便给人看的,对于计算机运算来说都是使用 补码 形式操作。以下的位运算和移位运算都是基于补码进行的.
位运算符 | 含义 | 解释 | 备注 |
---|---|---|---|
& | 按位与 | 两个整数按位对齐,当对齐的两位同时为1则结果为1,否则为0 | |
| | 按位或 | 两个整数按位对齐,当对齐的两位只要有一个为1则结果为1,否则为0 | |
~ | 按位非 | 只能适用于一个整数的自身操作,按位取反,即1变成0,0变成1 | 单目运算符 |
^ | 按位异或 | 两个整数按位对齐,当对齐的两位相同时为0,否则为1 |
我们以上面的int a = 7和int b = -7举例位运算的操作。 a的补码二进制为:00000000 00000000 00000000 00000111 b的补码二进制为:11111111 11111111 11111111 11111001 1、a&b 。
按位与的结果补码为:00000000 00000000 00000000 00000001
因为最高位为0,所以为正数,`正数的原码反码补码都相同`,所以原码也为:
00000000 00000000 00000000 00000001
转换成十进制的结果就是1。
2、a|b 。
按位或的结果补码为:11111111 11111111 11111111 11111111
最高位为1,所以是负数。
反码=补码-1,得到反码:11111111 11111111 11111111 11111110
原码=反码除符号位取反,得到原码:10000000 00000000 00000000 00000001
由原码最高位为1可知,该结果是负数,除符号位外转换成十进制的结果是1,所以最后按位或的结果就是-1。
3、a^b 。
按位或的结果补码为:11111111 11111111 11111111 11111110
最高位为1,所以是负数。
反码=补码-1,得到反码:11111111 11111111 11111111 11111101
原码=反码除符号位取反,得到原码:10000000 00000000 00000000 00000010
由原码最高位为1可知,该结果是负数,除符号位外转换成十进制的结果是2,所以最后按位或的结果就是-2。
4、~a 。
取反结果(补码形式):11111111 11111111 11111111 11111000
最高位为1,所以是负数。
反码=补码-1,得到反码:11111111 11111111 11111111 11110111
原码=反码除符号位取反,得到原码:10000000 00000000 00000000 00001000
由原码最高位为1可知,该结果是负数,除符号位外转换成十进制的结果是8,所以最后按位或的结果就是-8。
5、~b 。
取反结果(补码形式):00000000 00000000 00000000 00000110
最高位为0,所以是正数。正数的原码反码补码都相同,所以转换成十进制结果为6。
&(与)、|(或)这两个位运算适用于boolean判断,在这两个运算符的前后的条件都会计算,不像java里的条件判断符 && (并且) || (或者)会短路,判断符之前的满足条件后,那么判断符之后的表达式不再计算.
public static void main(String[] args) {
int a = 5;
if (a < 0 & a++ > 0) {
}
System.out.println("&条件后a=" + a);
if (a > 0 | a++ > 0) {
}
System.out.println("|条件后a=" + a);
if (a < 0 && a++ > 0) {
}
System.out.println("&&条件后a=" + a);
if (a > 0 || a++ > 0) {
}
System.out.println("||条件后a=" + a);
}
输出结果为:
&条件后a=6
|条件后a=7
&&条件后a=7
||条件后a=7
第一个判断 a < 0 & a++ > 0 前一个判断已经是false了,但是使用 & 连接,后一个表达式依然会计算a++,所以输出结果a的值加1等于6。 第二个判断 a > 0 | a++ > 0 前一个判断已经是true了,但是使用 | 连接,后一个表达式依然会计算a++,所以输出结果a的值加1等于7。 第三个判断 a < 0 && a++ > 0 前一个判断已经是false了,使用 && 连接的不会再计算后一个表达式的值,所以a的值不变。 第四个判断 a > 0 || a++ > 0 前一个判断已经是true了,使用 || 连接的不会再计算后一个表达式的值,所以a的值不变.
移位运算符 | 含义 | 解释 |
---|---|---|
<< | 左移 | 补码高位(不包括符号位)去掉指定位数,然后剩下的位数整体向左移动指定位数,低位使用0补齐 |
>> | 右移 | 补码低位去掉指定位数,然后剩下的位数整体向右移动指定位数,高位补上符号位(即正数补0,负数补1) |
>>> | 无符号右移 | 这个主要是针对于负数来说的,补码低位去掉指定位数,然后剩下的位数整体向右移动指定位数,高位(包括符号位)全部补上0 |
移位运算也是基于 补码 来操作的,因为是采用二进制,所以左移n位相当于该数乘以2的n次方、右移及无符号右移n位相当于该数除以2的n次方,但是无符号右移是相对于负数来说的,把符号位和其他高位都置为0.
我们仍以上面的int a = 7和int b = -7举例移位运算的操作。 a的补码二进制为:00000000 00000000 00000000 00000111 b的补码二进制为:11111111 11111111 11111111 11111001 1、a<<2 。
符号位不变,高位去掉两位,整体左移两位,低两位补0,结果为:
补码:00000000 00000000 00000000 00011100
高位为0即正数,正数的原码反码补码相同,所以原码=补码,转换为十进制结果为:28
2、a>>2 。
符号位为0,正数,则符号位不变,低位去掉两位,整体右移两位,高两位补0,结果为:
补码:00000000 00000000 00000000 00000001
高位为0即正数,正数的原码反码补码相同,所以原码=补码,转换为十进制结果为:1
3、a>>>2 。
符号位为0,正数,低位去掉两位,整体右移两位,高两位(包括符号位)补0,结果为:
补码:00000000 00000000 00000000 00000001
高位为0即正数,正数的原码反码补码相同,所以原码=补码,转换为十进制结果为:1
4、b<<2 。
符号位不变,高位去掉两位,整体左移两位,低两位补0,结果为:
补码:11111111 11111111 11111111 11100100
高位为1即负数
反码=补码-1,得到反码:11111111 11111111 11111111 11100011
原码=反码除符号位取反,得到原码:10000000 00000000 00000000 00011100
由原码最高位为1可知,该结果是负数,除符号位外转换成十进制的结果是28,所以最后按位或的结果就是-28。
5、b>>2 。
符号位为1,负数,低位去掉两位,整体右移两位,高两位补1,符号位为1,结果为:
补码:11111111 11111111 11111111 11111110
高位为1即负数
反码=补码-1,得到反码:11111111 11111111 11111111 11111101
原码=反码除符号位取反,得到原码:10000000 00000000 00000000 00000010
由原码最高位为1可知,该结果是负数,除符号位外转换成十进制的结果是2,所以最后按位或的结果就是-2。
6、b>>>2 。
符号位为1,负数,低位去掉两位,高两位(包括符号位)都补0,结果为:
补码:00111111 11111111 11111111 11111110
高位为0即正数,正数的原码反码补码相同,所以原码=补码,转换为十进制结果为:1073741822。
1、byte、short、char类型的整数再移位操作时会自动向上转为int类型后再操作移位。 2、int类型占32位,long类型占64位,当对这两个类型移位超出位数时,相当于对要移动的位数取余再移位,例如a<<32位,取余为0,相当于不移动,a<<34,取余为2相当于左移2位。long类型同理,只是对64取余.
1、不利用中间值,交换两个整数 可推倒出的结论是 a b a=b,a b c= a (b c)。所以对于两个整数a,b交换可以使用异或位运算.
public static void main(String[] args) {
int a = 5, b = 3;
System.out.println("a=" + a + "\tb=" + b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
System.out.println("a=" + a + "\tb=" + b);
}
输出结果:
a=5 b=3
a=3 b=5
2、判断一个正数的奇偶性 x & 1 == 0 则为偶数,否则为奇数。因为整数的二进制表示后,最后一位的0和1就表示了该值的奇偶性,&1之后相当于除了最后一位,其他位全清0了,最后一位若是1,则与的结果才为1,说明是奇数,最后一位为0,则与的结果是0,说明是偶数。 3、判断一个正数是不是2的幂次方 使用 n&(n-1) == 0 则为偶数,否则为奇数。因为2的次方数,除了高位的一个1外,后面的数据全部都是0,也就是说2的次方数的二进制形式里只有一个1,其他全部是0,减1后得到的二进制,1所在位变成0,1后的其他位都会变成1,所以与原二进制每一位都不相同,使用&后结果为0,则可以证明为偶数 4、计算一个二进制数中1的个数 。
int a = 15;
int count = 0;
while (a != 0) {
if ((a & 1) == 1) {
count++;
}
a = a >> 1;
}
System.out.println(count);
通过&1结果为1,说明最末一位是1,则可通过不断>>1并判断1的个数是否加1,直到这个数的值变为0为止。 5、其他应用场景可自行探索(* ̄︶ ̄) 。
最后此篇关于java位运算及移位运算你还记得吗的文章就讲到这里了,如果你想了解更多关于java位运算及移位运算你还记得吗的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我想将这个无符号数:1479636484000 向右移动 7 位。这在 JavaScript 中可能吗? 两者 1479636484000 >> 7 和 1479636484000 >>> 7 返回错
鉴于以下代码: import matplotlib.pyplot as plt import numpy as np x = [1.0, 1.1, 2.0, 5.7] y = np.arange(le
我有一个低级键盘钩子(Hook),目前允许我从任何应用程序(包括游戏)中控制媒体播放器。 它通过查看捕获的特定击键来工作。 我想扩展它以查找键的组合。我可以对一些逻辑进行硬编码,但我觉得必须有一种更合
我需要一些帮助来理解这段C代码。我不知道这里的“L”和“\”是什么?请也说明一点:) #define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>2
我正在查看一段代码: int result = 0 ; char byte = foo[j] for (i = 7 ; i>0 ; i--) { byte = (byte & ~0x1)>>1
我们有一个项目要求我们编写一个程序,允许用户输入一系列数字“将数字读入数组以进行进一步处理,用户通过输入负数表示他们已完成(负数不用于计算),在读取所有数字后执行以下操作,总结输入的#,计算输入的#,
锁定。有disputes about this question’s content正在解决中。它目前不接受新的答案或互动。 def menu(): choice = input("Pres
为什么如果 int x = -1 // binary: 11111111111111111111111111111111 x = x >>> 31; 我们有 000000000000000000000
我的问题其实应该很简单:我有一个玩家对象数组。(玩家[])我想要一个函数来旋转这个数组直到一个索引: public void rotateArray(Object[] array, int index
我有一个编码为 boost 动态位集的数字列表。我根据此列表中的任何数字可以采用的最大值动态选择此位集的大小。所以假设我有从 0 到 7 的数字,我只需要三位,我的字符串 0,2,7 将被编码为000
我能想到一些令人讨厌的低效方法来完成这项任务,但我想知道最好的方法是什么。 例如,我想复制一个字节中从第 3 位开始的 10 个字节,并像往常一样复制到一个指针。 有没有比一次复制一个移位字节更好的方
我正在尝试为该问题添加更多规则,并且该规则一直给我带来这种转变/减少冲突的能力,我不知道为什么会这样做,并且在过去的24小时内我一直在尝试解决问题 FuncDecl : RetTyp
This question already has answers here: Why does it make a difference if left and right shift are us
我在 Perl 中遇到这个问题已经有几天了,在搜索了无数的手册页、perldocs 和谷歌搜索了太多的搜索词之后,希望这里有人能帮助我。 我得到两个表示十六进制值的字符串,即“FFFF”,而不是 Pe
我有一个主 div,两个 div 水平并排放置在这个父 div 中。 .parent{ height: 360px; margin-top: 0px; bo
我想 float 我的元素列表并从第二个元素创建一个移动效果。 如何避免第二个 .item 之后的“清除”行为? .shift { float: right; width: 50%;
我正在使用 SSE3 优化我的代码。代码中有一点迫使我将 vector 中的所有元素移动一个元素 v[0] = 0 //v is some char* and N = v.size() for(i
.file "calcnew.c" .text .globl calcnew .type calcnew, @function calcnew:
我有一个点对象: class Point { final int x,y; ... } 因为这些点将在我的代码中到处使用/创建,所以我想开始使用 guavas 缓存。不幸的是
x = "Foo 890 bar *()" 如何将包括 "*()" 在内的小写字母“未移位”返回到 890?期望的结果: foo 890 bar 890 不需要的: x.lower() => "foo
我是一名优秀的程序员,十分优秀!