与运算

与运算 & 规则 :都为1时才为1

System.out.println( 7 & 9);
/*
 *  7二进制 0111
 *  9二进制 1001
 * -----------
 *          0001   ==1
 * */

案例:取模

h & (length-1),前提是length必须是2的n次方,HashMap的扩容机制就用到了这种方法

System.out.println(10 & (4 - 1)); // 2

或运算

或运算 规则:有一个为1,则为1
System.out.println(7 | 9);
/*
 * 7二进制 0111
 * 9二进制 1001
 * ----------
 *         1111 == 15
 * */

异或运算

异或运算 ^ 规则:不同为1

System.out.println( 7 ^ 9);
/*
 * 7二进制 0111
 * 9二进制 1001
 * ----------
 *      1110 == 14
 *
 * */

取反运算

//取反运算(计算机存储的是补码,取反其实是针对补码进行取反)
//http://blog.csdn.net/poxu1234/article/details/62422231
//1.计算机中存储整数都是用的补码,取反运算也是对补码进行取反
//2.所有的数字大小都是根据原码的大小计算的
//3.正整数的反码,补码和原码相同。负整数的反码是除了符号位以外取反,补码为反码+1
//4.对补码再求补码即是原码
//取反运算 ~ 规则:按位取反
System.out.println( ~7);
/*
 * 7二进制         0000 0000 0000 0000 0000 0000 0000 0111
 * 7的补码是本身   0000 0000 0000 0000 0000 0000 0000 0111  正数的补码和反码都是本身
 * 取反操作        1111 1111 1111 1111 1111 1111 1111 1000  取反之后变成负数了,负数的补码=符号位不动,其他位取反+1,也就是反码+1
 * 补码的补码      1000 0000 0000 0000 0000 0000 0000 1000  得到-8
 *
 * */
System.out.println(~-7);
/*
 * -7二进制        1000 0000 0000 0000 0000 0000 0000 0111
 * -7的补码        1111 1111 1111 1111 1111 1111 1111 1001  负数的反码=符号位不动,其他位取反;负数的补码=符号位不动,其他位取反+1,也就是反码+1
 * 取反操作        0000 0000 0000 0000 0000 0000 0000 0110
 * 补码的补码      0000 0000 0000 0000 0000 0000 0000 0110 得到6
 *
 * */

位移

>> 右位移,相当于除以2 >>> 无符号右位移,对于正数相当于除以2,对于负数,高位补0

int a = 8 >> 1;
System.out.println(a);// 4
int b = -8 >> 1;
System.out.println(b);// -4
int c = 8 >>> 1;
System.out.println(c);// 4
int d = -8 >>> 1;
System.out.println(d);// 2147483644
System.out.println(Integer.toBinaryString(-8));// 11111111111111111111111111111000

案例

使用同一个int或long字段存储多种状态值

/**
 * 通过位移操作将多个bit状态值存储到同一个字段中,注意状态值只能有(是 or 否),64位机器最多可以同时管理63种状态(long类型,首位是符号位)
 * 
 * 示例:用一个状态值来存储小明是否交了各门作业
 **/
public class BitStatusUtils {

    // A:语文 B:数学 C:英语 D:物理 E:化学 F:生物 G:历史 H:地理

    // 二进制表示 0001 没有交任何作业
    public static final long NONE = 1 << 0;
    // 语文 0000 0000 0010
    public static final long CHINESE = NONE << 1;
    // 数学 0000 0000 0100
    public static final long MATH = NONE << 2;
    // 英语 0000 0000 1000
    public static final long ENGLISH = NONE << 3;
    // 物理 0000 0001 0000
    public static final long PHYSICS = NONE << 4;
    // 化学 0000 0010 0000
    public static final long CHEMISTRY = NONE << 5;
    // 生物 0000 0100 0000
    public static final long BIOLOGY = NONE << 6;
    // 历史 0000 1000 0000
    public static final long HISTORY = NONE << 7;
    // 地理 0001 0000 0000
    public static final long GEOGRAPHY = NONE << 8;

    // 所有作业都交了 0001 1111 1111
    public static final long ALL =
        NONE | CHINESE | MATH | ENGLISH | PHYSICS | CHEMISTRY | BIOLOGY | HISTORY | GEOGRAPHY;

    /**
     * @param status
     *            所有状态值
     * @param value
     *            需要判断状态值
     * @return 是否存在
     */
    public static boolean hasStatus(long status, long value) {
        return (status & value) != 0;
    }

    /**
     * @param status
     *            已有状态值
     * @param value
     *            需要添加状态值
     * @return 新的状态值
     */
    public static long addStatus(long status, long value) {
        if (hasStatus(status, value)) {
            return status;
        }
        return (status | value);
    }

    /**
     * @param status
     *            已有状态值
     * @param value
     *            需要删除状态值
     * @return 新的状态值
     */
    public static long removeStatus(long status, long value) {
        if (!hasStatus(status, value)) {
            return status;
        }
        return status ^ value;
    }

    /**
     * 是否交了含有全部状态
     * 
     * @param status
     * @return
     */
    public static boolean hasAllStatus(long status) {
        return (status & ALL) == ALL;
    }

    public static void main(String[] args) {

        // NONE | CHINESE | MATH | ENGLISH | PHYSICS | CHEMISTRY | BIOLOGY | HISTORY | GEOGRAPHY;
        System.out.println(Long.toBinaryString(NONE));
        System.out.println(Long.toBinaryString(CHINESE));
        System.out.println(Long.toBinaryString(MATH));
        System.out.println(Long.toBinaryString(ENGLISH));
        System.out.println(Long.toBinaryString(PHYSICS));
        System.out.println(Long.toBinaryString(CHEMISTRY));
        System.out.println(Long.toBinaryString(BIOLOGY));
        System.out.println(Long.toBinaryString(HISTORY));
        System.out.println(Long.toBinaryString(GEOGRAPHY));
        System.out.println(Long.toBinaryString(ALL));

        // int类型可以存储31种状态,1111111111111111111111111111111
        System.out.println(Integer.toBinaryString(Integer.MAX_VALUE));
        // long类型可以存储63种状态,111111111111111111111111111111111111111111111111111111111111111
        System.out.println(Long.toBinaryString(Long.MAX_VALUE));

        long status = addStatus(NONE, CHINESE);
        System.out.println("小明交了语文作业:" + status);

        status = addStatus(status, PHYSICS);
        System.out.println("小明又交了物理作业:" + status);

        status = addStatus(status, HISTORY);
        System.out.println("小明还交了历史作业:" + status);

        status = removeStatus(status, HISTORY);
        System.out.println("小明撤销了历史作业:" + status);

        System.out.println("小明是否交了语文作业:" + hasStatus(status, CHINESE));
        System.out.println("小明是否交了历史作业:" + hasStatus(status, HISTORY));
        System.out.println("小明是否交了生物作业:" + hasStatus(status, BIOLOGY));
        System.out.println("小明是否交了全部作业:" + hasAllStatus(status));
    }
}

参考

为什么可以使用位运算(&)来实现取模运算(%)呢?

如何用一个字段表示八个状态啊