public class BitOperate { public static void bitCalc() { byte a = 12,b=10; byte c = -12,d=-10; /** * 1、按位与 & * (AND) * 运算方法:当两边操作数的位同时为1时,结果为1,否则为0 * * 注意:符号位也会参与运算 */ // 12二进制表示(1100),10二机制(1010) System.out.println("正数与运算:"+(a&b)); //1100&1010=1000 == 8 //注意:负数计算机用补码表示: // -12:11110100, -10:11110110 System.out.println("负数与运算:"+(c&d)); //(11110100)补=(10001100)原 == -12 // System.out.println("正负数与运算:"+(a&d));//00001100&11110110 = 00000100 == 4 System.out.println(); /** * 2、按位或 | * (OR) * 运算方法:当两边操作数的位有一边为1时,结果为1,否则为0 * */ System.out.println("正数或运算:"+(a|b)); //1100|1010=1110 == 14 // -12:11110100, -10:11110110 System.out.println("负数或运算:"+(c|d)); //(11110110)补=(10001010)原 == -10 // 12:00001100, -10:11110110 System.out.println("正负数或运算:"+(a|d)); //(11111110)补=(10000010)原 == -2 System.out.println(); /** * 3、按位非 ~ * (NOT) * 运算方法:操作数的位0变1,1变0 * */ // 12: 00001100 System.out.println("正数非运算:"+ (~a)); //11110011=(10001101)原 == -13 // -12: 11110100 System.out.println("负数非运算:"+ (~c)); //00001011 == 11 System.out.println(); /** * 4、按位异或 ^ * (XOR) * 运算方法: 对比每个数位上的0或1如果相同,那么结果就取0,如果不同就取1 * */ // 12: 00001100), 10: 00001010) System.out.println("正数异或运算:"+ (a^b)); //000000110 == 6 // -12:11110100, -10:11110110 System.out.println("负数异或运算:"+(c^d)); //00000010 == 2 // 12:00001100, -10:11110110 System.out.println("正负数异或运算:"+(a^d)); //(11111010)补=(10000110)原 == -6 System.out.println("--------------------------------------------"); /** * 移位运算 * * 概念: * 移位运算符就是在二进制的基础上对数字进行平移。 * * 分类: * 按照平移的方向和填充数字的规则分为三种:<<(左移)、>>(带符号右移)和>>>(无符号右移)。 * * 运算方式: * 在移位运算时,byte、short和char类型移位后的结果会变成int类型, * 对于byte、short、char和int进行移位时,规定实际移动的次数是移动次数和32的余数, * 也就是移位33次和移位1次得到的结果相同。 * 移动long型的数值时,规定实际移动的次数是移动次数和64的余数, * 也就是移动66次和移动2次得到的结果相同。 * * */ /** * 5、左移 << * * 运算方法: * 按二进制形式把所有的数字向左移动对应的位数,高位移出(舍弃),低位的空位补零。 * * 数学意义: * 在数字没有溢出的前提下,对于正数和负数,左移一位都相当于乘以2的1次方,左移n位就相当于乘以2的n次方。 * */ //before: 0000 0000 0000 0000 0000 0000 0000 1100 //after: 0000 0000 0000 0000 0000 0000 0011 0000 == 48 System.out.println("正数左移:"+(a<<2)); //a*2*2 = 48 System.out.println("负数左移:"+(c<<2)); //c*2*2 = -48 //数字溢出的情况: //12 //before: 0000 0000 0000 0000 0000 0000 0000 1100 //<<28 after : 1100 0000 0000 0000 0000 0000 0000 0000 //<<29 after : 1000 0000 0000 0000 0000 0000 0000 0000 -0补码代表最小负数2的31次方就是-2147483648 System.out.println("正数左移溢出:"+(a<<28)); //-1073741824 System.out.println("正数左移溢出:"+(a<<29)); //-2147483648 //-12 //before: 1111 1111 1111 1111 1111 1111 1111 0100 //<<28after : 0100 0000 0000 0000 0000 0000 0000 0000 //<<28after : 1000 0000 0000 0000 0000 0000 0000 0000 System.out.println("负数左移溢出:"+(c<<28)); //1073741824 System.out.println("负数左移溢出:"+(c<<29)); //-2147483648 System.out.println(); /** * 5、有符号右移 >> * * 运算方法: * 按二进制形式把所有的数字向右移动对应的位数,低位移出(舍弃),高位的空位补符号位,即正数补零,负数补1。 * * 数学意义: * 在数字没有溢出的前提下,右移一位相当于除2,右移n位相当于除以2的n次方。 * */ //10 : 0000 0000 0000 0000 0000 0000 0000 1010 //>>2after: 0000 0000 0000 0000 0000 0000 0000 0010 System.out.println("正数有符号右移:"+(b>>2)); //a/2*2 = 2 //-10:1111 1111 1111 1111 1111 1111 1111 0110 //>>2after: 111111 1111 1111 1111 1111 1111 1111 1101 System.out.println("负数有符号右移:"+(d>>2)); //-3 System.out.println(); /** * 5、无符号右移 >>> * * 运算方法: * 按二进制形式把所有的数字向右移动对应的位数,低位移出(舍弃),高位的空位补零。 * 对于正数来说和带符号右移相同,对于负数来说不同。 * * 其他结构和>>相似。 * */ //10 : 0000 0000 0000 0000 0000 0000 0000 1010 //>>>2after: 0000 0000 0000 0000 0000 0000 0000 0010 System.out.println("正数无符号右移:"+(b>>>2)); // 正数的情况与>>相同 //-10:1111 1111 1111 1111 1111 1111 1111 0110 //>>>2after: 001111 1111 1111 1111 1111 1111 1111 1101 System.out.println("负数无符号右移:"+(d>>>2)); //负数高位补0:1073741821 } public static void main(String[] args) { BitOperate.bitCalc(); } }
运算结果:
正数与运算:8 负数与运算:-12 正负数与运算:4 正数或运算:14 负数或运算:-10 正负数或运算:-2 正数非运算:-13 负数非运算:11 正数异或运算:6 负数异或运算:2 正负数异或运算:-6 -------------------------------------------- 正数左移:48 负数左移:-48 正数左移溢出:-1073741824 正数左移溢出:-2147483648 负数左移溢出:1073741824 负数左移溢出:-2147483648 正数有符号右移:2 负数有符号右移:-3 正数无符号右移:2 负数无符号右移:1073741821
/** * byte、short类型左移 * * 会自动转换为int类型进行右移 */ public static void bitShift() { byte a = 64, b; int i; i = a << 2; b = (byte) (a << 2); System.out.println("Original value of a: " + a); System.out.println("i (int): " + i + "----- b(byte): " + b); }
结果:
Original value of a: 64 i (int): 256----- b(byte): 0
移位运算的总结:
1.对于左移运算:
1>每左移一个位,高阶位都被移出(并且丢弃),并用0填充右边。这意味着当左移的运算数是int 类型时,每移动1位,它的第31位就要被移出并且丢弃;当左移的运算数是long 类型时,每移动1位它的第63位就要被移出并且丢弃。
2>左移都可以使原来的操作数翻倍,程序员们经常使用这个办法来进行快速的2 的乘法。但是你要小心,如果你将1移进高阶位(31或63位),那么该值将变为负值。
3>在对byte 和short类型的值进行移位运算时 , Java将自动把这些类型扩大为 int 型,而且,移位后的值也是int 型;如果左移不超过31位,原来对应各位的值不会丢弃。但是,如果你对一个负的byte 或者short类型的值进行移位运算,它被扩大为int 型后,它的符号也被扩展,结果的高位就会被1填充。因此,为了得到正确的结果,你就要舍弃得到结果的高位。这样做的最简单办法是将移位运算的结果再转换成byte 型 。
2.对于右移运算:每右移一次,就相当于将该值除以2并且舍弃了余数。你可以利用这个特点将一个整数进行快速的2的除法。当然,你一定要确保你不会将该数原有的任何一位移出。
3.无符号右移(>>>)与右移的区别:每一次右移,>>运算符总是自动地用它的先前最高位的内容补它的最高位。这样做保留了原值的符号。而无符号移动总是在高位(最左边)补0。
4.与C、C++不同,Java中没有无符号型整数,而且明确规定了整型和浮点型数据所占的内存字节数,这样就保证了安全性、鲁棒性和平台无关性。