关于异或和一些运算符
上课的时候经常摸鱼,连异或都没搞懂,今天看map源码的时候才注意到有一个看不懂的计算符
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
就上面代码中的 ^ 号,开始一脸懵逼,以为是乘方,但想了想,先把h赋值了,然后让它 乘方 (自己除以2的16次方结果)?这多多少少有点大病吧。
所以我大概率断定这个 ^ 应该不是乘方,所以就去查了查,发现是异或的意思,当初自己都没搞懂,现在又来…………罢了罢了,总得要补的,就自己去学历一下异或怎么玩,顺便还总结了一下几个计算符:
如下:
Java运算符大致分为逻辑运算符(&&,||,!)、算数运算符(+, -, *, / ,+=)、位运算符(^,|,&)、其他运算符(三元运算符)
&(按位与)
System.out.println(3&5);
System.out.println(7&5);
控制台打印:
1
5
&按位与的运算规则是将两边的数转换为二进制位,然后运算最终值,运算规则即(两个为真才为真)1&1=1 , 1&0=0 , 0&1=0 , 0&0=0
3的二进制位是0000 0011 , 5的二进制位是0000 0101 , 那么就是011 & 101,由按位与运算规则得知,001 & 101等于0000 0001,最终值为1
7的二进制位是0000 0111,那就是111 & 101等于101,也就是0000 0101,故值为5
&&(逻辑与)
这个没啥说的吧
&&逻辑与也称为短路逻辑与,先运算&&左边的表达式,一旦为假,后续不管多少表达式,均不再计算,一个为真,再计算右边的表达式,两个为真才为真。
|(按位或)
System.out.println(6^2);
控制台打印:
4
|按位或和&按位与计算方式都是转换二进制再计算,不同的是运算规则(一个为真即为真)1|0 = 1 , 1|1 = 1 , 0|0 = 0 , 0|1 = 1
6的二进制位0000 0110 , 2的二进制位0000 0010 , 110|010为110,最终值0000 0110,故6|2等于6
||(逻辑或)
这个也不需要多说什么了吧
逻辑或||的运算规则是一个为真即为真,后续不再计算,一个为假再计算右边的表达式。
^(异或运算符)
System.out.println(9^9);
System.out.println(7^9);
控制台打印:
0
14
异或,先把计算的两个数化成2进制数,位数相同的情况下(不够拿0补)
然后按照异或法则 1^1=0 0^0=0 1^0=1 0^1=1
对应位数分别计算
比如上面的9^9 9的2进制为 1001 所以计算过程应该是: 1^1=0 0^0=0 0^0=0 1^1=0
再组合,结果为0000,所以结果为0
再比如:7^9 9的2进制为1001 7的二进制为111,计算过程应该是:
因为9的二进制是4位,所以应该先给7补位,变成0111
然后再分别疑惑:0^1=1 1^0=1 1^0=1 1^1=0
再组合为1110,所以结果应该是14
<<(左移运算符)
先把需要计算的数化作2进制,然后往左边移动,二进制左边移动就是乘2呗
左移多少就是乘以2的多少次方
System.out.println(6<<2);
System.out.println(9<<3);
控制台打印:
24
72
>>(右移运算符)
跟左移相反,右移多少位就是除以2的多少次方
System.out.println(16>>2);
System.out.println(100>>3);
控制台打印:
4
12
这里说一下,右移是除,所以是小数,但浮点型是不能进行左右移的,所以自动转换了
~(取反运算符)
说实话,我都不知道还有个取反符号!
这个的意思是先把数转化为2进制,然后1取0 , 0取1 ,最后得到一个数,再转为10进制
public static String jinZhiZhuanHuan(int x, int len) {//写的一个整数转换成2进制的方法,x代表需要转换的整数,len表示需要转换的2进制位数
final char[] buff = new char[len];
for (int i = len - 1; i >= 0 ; i--) {
int mask = 1 << i;
buff[len - 1 - i] = (x & mask) != 0 ? '1' : '0';
}
return new String(buff);
}
public static void main(String[] args) {
System.out.println(jinZhiZhuanHuan(5,16));
System.out.println(~5);
System.out.println(jinZhiZhuanHuan(~5,16));
}
控制台打印结果:
0000000000000101
-6
1111111111111010
所实话吧,我都不知道这个有啥用,用来加密吗?
>>>(无符号右移运算符)
System.out.println(15>>>2);
控制台打印:
3
正数无符号右移(和右移差不多)
无符号右移运算符和右移运算符的主要区别在于负数的计算,因为无符号右移是高位补0,移多少位补多少个0。
15的二进制位是0000 1111 , 右移2位0000 0011,结果为3
负数无符号右移
System.out.println(jinZhiZhuanHuan(~6,8));//6取反的二进制
String a =jinZhiZhuanHuan(~6,8);
int a1 =Integer.valueOf(a);
a=String.valueOf(a1+9);//取反后加1
System.out.println(a);
System.out.println(-6>>>3);
System.out.println(jinZhiZhuanHuan(-6>>>3,32));
控制台打印:
11111001
11111010
536870911
00011111111111111111111111111111
-6的二进制是6的二进制取反再加1,6的二进制也就是0000 0000 0000 0000 0000 0000 0000 0110,
取反后加1为1111 1111 1111 1111 1111 1111 1111 1010,
右移三位0001 1111 1111 1111 1111 1111 1111 1111
所以结果为:536870911
这里我也不太明白,就这样记录吧