1、Arrays的二分排序中的取中点
①、int mid=(low+high)/2;【会溢出不考虑使用】
②、int mid=low+(high-low)/2;【会避免大数溢出,一般白板写二分查找多用】
③、int mid = (low + high) >>> 1; 【移位运算,由于位运算直接对内存数据进行操作,不需要转成十进制,因此处理速度非常快。】
传统的方法 int mid = (left + right) /2 ,在 left 和 right 比较大的时候, 两者相加很可能超过 int 类的最大值,即发现整型溢出;
改进 int mid = left + (right - left) /2
最好的写法 int mid = (left + right) >>> 1
>>, 右移时,丢弃右边指定位数,左边补上符号位;
>>>, 无符号右移运算符,丢弃右边指定的位数,左边补上 0 。所以对负数右移,可以变成正数;
private static int binarySearch0(float[] a, int fromIndex, int toIndex,
float key) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
float midVal = a[mid];
if (midVal < key)
low = mid + 1; // Neither val is NaN, thisVal is smaller
else if (midVal > key)
high = mid - 1; // Neither val is NaN, thisVal is larger
else {
int midBits = Float.floatToIntBits(midVal);
int keyBits = Float.floatToIntBits(key);
if (midBits == keyBits) // Values are equal
return mid; // Key found
else if (midBits < keyBits) // (-0.0, 0.0) or (!NaN, NaN)
low = mid + 1;
else // (0.0, -0.0) or (NaN, !NaN)
high = mid - 1;
}
}
return -(low + 1); // key not found.
}
例如合并排序中也有使用到取中间节点.
2、位运算扩容.
HashMap的tableSizeFor,实现一个数的扩容至最小的2的幂次方feb.
/**
* Returns a power of two size for the given target capacity.
*/
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
3、HashMap的获取hash.
JDK 源码中 HashMap 的 hash 方法原理是什么?
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
陆续更新.
附录:
①、异或运算规则
参加运算的两个对象,按照二进制位进行异或运算,运算规则:0^0=0,0^1=1,1^1=0,相同为0,不同为1。
异或运算的性质:
- 任何一个变量与0异或是其本身(N^0=N)
- 任何一个变量与自身异或为0(N^N=0)
4、线程池中使用位运算高位存储状态
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;