Java 中包含的运算符有:

+ 加法运算
- 减法运算
* 乘法运算
/ 除法运算
& 与运算
| 或运算
^ 异运算
++ 连加运算
-- 连减运算

加法和减法运算是我们最最基础的数学运算符,早在我们还在孩童时就明白1+1 = 2 的道理,我们今天来讨论 除法 和 异或 运算符 。

当我对 3 进行 ➗ 2 除法运算时,可以预想得到的结果是 1.5 ,但是int值并不能具有小数点,所以Java 中,它是向下取整的:

public class Test {
    public static void main(String[] args) {
        int A = 3;
        System.out.println(A / 2);
    }
}
//1

我们得到今天一个最基本的道理:Java 除法运算 是向下取整的。

 

第一节:左移右移

那么如何简化该结果?当你需要除以2的时候,我们完全可以用位运算来替代它的使用,毕竟计算机去操纵字节码可是它的拿手好戏:

public class Test {
    public static void main(String[] args) {
        int A = 3;
        System.out.println(A >> 1);
    }
}
// 2

我们可以这样理解,左移1位相当于除以 2 的1次方,左移 2 位相当于 除以 2 的 2次方,依次类推。其中最内层的字节码原理:

java除数为零异常 java 除_Java

计算机内部的字节码如图,数字3实际上就是2^0 加上2^1 ,同理2^0 到2^7 一同相加,可以得到的数字是255,要记得从2^0 ~ 2^7 的所有结果,以备运算之需

那么为什么 3 向由位移一位 就能得到1呢?很好理解:

java除数为零异常 java 除_Java_02

原来在第二位的数字 1 向左移动了 1 位,导致原本在 第二位的 数字 1 直接被挤兑没了…… 所以现在字节码中只存在了1个1,就在第一位上,也代表十进制的1

那么我们是否可以理解为:

public class Test {
    public static void main(String[] args) {
        int a = 3;
        int b = 3;
        System.out.println(a >> 1 == b / 2);
    }
}
//ture

所以当我们遇到需要除以2的场景,可以使用左移1 位 来进行替代,并且越大的数值它的效果越好,因为位运算是最快速的运算,

同理当你需要乘以2的场景, 你可以使用右移 1 位来替代,

同理当你需要任何乘除 2 的次方的场景,你都可以用 左右移的方式来进行替代。

似乎我们平常的操作过程中对它们很少用到,但它们在高效算法中非常常见,上代码:

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;
    }

这是HashMap中的一段源码,它的主要作用就是将任何一个数字转化为它最邻近的2的次方,例如31会转化为32,9会转化为8,这可比使用乘法除法运算要高效的多得多。

这里使用的并非我们使用>>,而是>>>这代表着无符号右移,例如 byte 总共有8位,其中可使用部分有7位,还有1位标识这是否是负数,所以数值类型 byte 的取值范围是 - 2^7 ~ 2^7-1 ;而无符号右移让负数标识符也向右移动,这会让负数的影响非常巨大!但对于正数来说这没什么影响。