开篇废话

运算符使用的几点小技巧,先给出Java的运算符的基本知识复习下,其它语言的大同小异。运算符需要注意的问题有:优先级(运算顺序问题)、结合方向(自左至右或自右至左问题)、要求运算对象个数(运算符需要有几个运算对象问题)
合理运用运算符能提高自己代码的BIG、能精简代码、还能提高程序的运行效率,滥用运算符可能导致逻辑混乱、代码不知所云什么的,所以有些问题还是要自己注意一下的。下面就列出一些运算符的使用技巧,换一换思路看下,当然还有先占着这个坑,以后会补(man)上(man)更(lai)新(ba)。

^ 按位异或

不用第三个临时变量交换两个数的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static void main(String[] args) {
int a = 2; // int a = -2;
int b = 3;
/* 总的来说就是先找出两个数上位值不同的位置置1其余0,然后将得到的新值分别和a、b的原值异或 */
a ^= b; // a = a ^ b;
b ^= a; // b = a ^ b;
a ^= b; // a = a ^ b;
System.out.printf("交换后: a=%s, b=%s", a, b);
}
```
## <<、>> 按位左移、右移
### 将一个数乘于2的n次方a*(2<sup>n</sup>)
``` Java
int a = 2;
int n = 3; // n=1, 左移一位就是乘于2
a <<= n; // a = a << n;
System.out.println("a*(2^n) = " + a);

将一个数除以2的n次方a/(2n)

1
2
3
4
5
6
7
8
9
10
11
12
13
int a = 32;
int n = 3; //n=1, 右移一位就是除于2
a >>= n; // a = a >> n;
System.out.println("a/(2^n) = " + a);
```
<!--more-->
### 2的n次方
``` Java
int n = 3; // int n = 0;
int result = 2 << (n - 1);
System.out.println("2^n = " + result);

& 按位与

判断一个数的奇偶

1
2
3
int a = 3;
boolean bl = (a & 1) == 1;
System.out.println("a为奇数? " + bl);

对2n取余

1
2
3
4
5
int n = 2 << 2; // 2的3次方
int value = 2;
// 如果是2的幂,n一定是100... n-1就是1111...所以做与运算结果保留m在n范围的非0的位
int result = value & (n - 1);
System.out.println("2对8取余接结果 = " + result);

HashMap的table的大小(HashMap的优化是把hash表的大小设置为2n的)和确定元素的存放位置即table表中的位置(indexFor(int h, int length)方法)也是运用了这一原理,HashMap相关代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
/**
* The table, resized as necessary. Length MUST Always be a power of two.
*/
transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
......
/**
* Returns index for hash code h.
*/
static int indexFor(int h, int length) {
// assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
return h & (length-1);
}

HashMap中hash(Object k)函数也运用了int类型(4个字节32位)数据的按位右移补零(>>>)和异或(^)运算加入了高位计算,防止低位不变,高位变化时,造成的hash冲突也就是要使得高位对其结果也产生影响:

1
2
3
4
5
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);

END

参考文章:
优秀程序员不得不知道的20个位运算技巧
Java HashMap 核心源码解读
JAVA移位运算符