Rocko's blog

Live in the moment


运算符的几点

开篇废话

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

^ 按位异或

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

	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*(2n)

		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)

		int a = 32;
		int n = 3; //n=1, 右移一位就是除于2
		a >>= n; // a = a >> n;
		System.out.println("a/(2^n) = " + a);

2的n次方

		int n = 3; // int n = 0;
		int result = 2 << (n - 1);
		System.out.println("2^n = " + result);

& 按位与

判断一个数的奇偶

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

对2n取余

		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相关代码如下:

    /**
     * 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冲突也就是要使得高位对其结果也产生影响:

        // 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移位运算符