转载请保留原文链接: http://dashidan.com/article/java/basic/17.html
位运算是通过二进制计算的方式来改变数据.位运算表达式由操作数和位运算符组成,实现对整数类型的二进制数进行位运算.位运算符可以分为逻辑运算符(包括~,&,|和^)及移位运算符(包括>>,
① Java进位方式
在Java语言中, 二进制数使用补码表示, 最高位为符号位, 正数的符号位为0, 负数为1.
补码的表示规则:
- 正数的最高位为0,其余各位代表数值本身(二进制数).
- 对于负数,通过对该数绝对值的补码按位取反,再对整个数加1.
2进制
2进制即为满2进1
. 第n位表示2^(n-1)
(2的n-1次幂). 数据在计算机内存中以二进制的形式存储.以int
类型举例, 占4个字节共32位(1个字节占8位). 数字100, int
类型的二进制数:
0000 0000 0000 0000 0110 0100
数字太长, 不便于理解.因此C,C++以及java中都没有提供在代码直接写二进制数的方法.
8进制
8进制即为满8进1
. 第n位表示8^(n-1)
(8的n-1次幂). 一个数如果采用八进制, 必须在它前面加上一个数字0
.
例:
package com.dashidan.lesson16;
/**
* 大屎蛋教程网-dashidan.com
* <p>
* Java教程基础篇: 16. Java位运算
*/
public class Demo1 {
public static void main(String[] args) {
/** 10进制*/
int a = 100;
/** 8进制*/
int b = 0100;
System.out.println("a: " + a + " b: " + b);
}
}
输出:
a: 100 b: 64
用8进制表达时,不能少了最前边的数字`0`.否则计算机会当成10进制处理.但用转义字符
表达时,不能加0.
16进制
16进制即为满16进1
. 第n位表示16^(n-1)
(16的n-1次幂). 10-15的数字分别以字母a到f表示, 不区分大小小. 16进制数必须以0x
开头.x
不区分大小写.
package com.dashidan.lesson16;
/**
* 大屎蛋教程网-dashidan.com
* <p>
* Java教程基础篇: 16. Java位运算
*/
public class Demo1 {
public static void main(String[] args) {
/** 10进制*/
int a = 100;
/** 8进制*/
int b = 0100;
/** 16进制*/
int c = 0x100;
System.out.println("a: " + a + " b: " + b + " c: " + c);
}
}
输出:
a: 100 b: 64 c: 256
0x中的0是数字0,而不是字母O
8进制和16进制只能用来表达无符号的正整数?
网上有资料这样说, 但这个是错误的. 8进制和16进制同样可以表示负数.
附带真相的代码:
package com.dashidan.lesson16;
/**
* 大屎蛋教程网-dashidan.com
* <p>
* Java教程基础篇: 16. Java位运算
*/
public class Demo1 {
public static void main(String[] args) {
int d = -0100;
int e = -0x100;
System.out.println("d: " + d + " e: " + e);
}
}
输出: d: -64 e: -256
② 位运算逻辑运算符
位运算逻辑运算符包括: 与(&),非(~),或(|),异或(^).
- &: 与. 当两边操作数的位同时为1时, 结果为1, 否则为0.
例:
1100&1010=1000
位运算判断奇偶, 偶数的最低位是0,奇数的最低位是1.通过这个原理, 我们可以根据整数二进制最后一位与1比较, 判断奇偶.
package com.dashidan.lesson16;
import java.util.Random;
/**
* 大屎蛋教程网-dashidan.com
* <p>
* Java教程基础篇: 16. Java位运算
* 位运算判断奇偶
*/
public class Demo2 {
public static void main(String[] args) {
/** 随机一个整数*/
int a = new Random().nextInt();
/** 判断奇偶性*/
String numStr = ((a & 1) == 1) ? "奇数" : "偶数";
System.out.println("随机数为: " + a + " 是: " + numStr);
}
}
输出:
随机数为: 476218275 是: 奇数
- |: 或. 当两边操作数的位有一边为1时,结果为1,否则为0.
例:
1100|1010=1110
- ~: 按位取反. 0变1,1变0.
负数在内存中的表现是, 按位取反再加1.
- ^: 按位异或. 参与运算的两个值,如果两个相应位相同,则结果为0,否则为1.
0异或任何数等于任何数, 1异或任何数等于任何数取反, 任何数异或自己等于把自己置0
即:
0^0=0
1^0=1
0^1=1
1^1=0
不用临时变量交换两个数
通过按位异或运算,可以实现两个值的交换,而不必使用临时变量. 这个很酷.
例:
交换两个整数a,b的值,可通过下列语句实现:
package com.dashidan.lesson16;
/**
* 大屎蛋教程网-dashidan.com
* <p>
* Java教程基础篇: 16. Java位运算
* 不用临时变量交换两个数
*/
public class Demo3 {
public static void main(String[] args) {
/** 数a两次异或同一个数b(a=a^b^b)仍然为原值.*/
int a = 100;
int b = 666;
a = a ^ b;
b = b ^ a;
a = a ^ b;
System.out.println("a: " + a + " b " + b);
}
}
输出:
a: 666 b 100
数a两次异或同一个数b(a=a^b^b)仍然为原值.
③ 移位运算符
java移位运算符包括:
<<
:左移位>>
:带符号右移>>>
:无符号右移
1.左移位运算符(<<)
使指定值的所有位都向左移规定的次数, 丢弃最高位, 在低位补0. 在数字没有溢出的前提下,对于正数和负数, 左移一位都相当于乘以2的1次方, 左移n位就相当于乘以2的n次方.
如果位数超过了该类型的最大位数, 该值将变为负值.
格式:
value << num
num 指定要移位值value 移动的位数.
如果移动的位数超过了该类型的最大位数,那么编译器会对移动的位数取模.
如对int型移动33位,实际上只移动了33%32=1位.
计算过程:
以4<<2
为例
1.把3转换为二进制数字0000 0000 0000 0000 0000 0000 0000 0100,
2.把该数字高位(左侧)的两个零移出,其他的数字都朝左平移2位,
3.在低位(右侧)的两个空位补零.得到的最终结果是0000 0000 0000 0000 0000 0000 0001 0000,
转换为十进制是12.
package com.dashidan.lesson16;
/**
* 大屎蛋教程网-dashidan.com
* <p>
* Java教程基础篇: 16. Java位运算
* 移位运算符
*/
public class Demo4 {
public static void main(String[] args) {
int a = 4;
int b = a << 2;
System.out.println("a: " + a + " b: " + b);
}
}
输出:
a: 4 b: 16
2.有符号右移位运算符>>
使指定值的所有位都向右移规定的次数.正数在高位插入0,负数则在高位插入1. 右移一位相当于除2, 右移n位相当于除以2的n次方.
格式如下:
value >> num
num 指定要移位值value 移动的位数.
package com.dashidan.lesson16;
/**
* 大屎蛋教程网-dashidan.com
* <p>
* Java教程基础篇: 16. Java位运算
* 移位运算符
*/
public class Demo4 {
public static void main(String[] args) {
int a = 4;
int b = a << 2;
System.out.println("a: " + a + " b: " + b);
int c = 1000;
int d = c >> 2;
System.out.println("c: " + a + " d: " + d);
}
}
输出:
c: 1000 d: 250
3.”无符号”右移位运算符(>>>).
忽略了符号位扩展,无论正负,都在高位插入0.
格式如下:
value >>> num
num
指定要移位值value
移动的位数.
package com.dashidan.lesson16;
/**
* 大屎蛋教程网-dashidan.com
* <p>
* Java教程基础篇: 16. Java位运算
* 移位运算符
*/
public class Demo4 {
public static void main(String[] args) {
int e = -1;
int f = e >>> 2;
System.out.println("e: " + e + " f: " + f);
}
}
输出:
e: -1 f: 1073741823
只是对32位和64位的值有意义.这一运算符是C或C++没有的.
char,byte或者short移位
在移位前,它们会自动转换成一个int. 移位操作符右端的那个数(转化成二进制)的5个低位才会用到, 即x
④ 位运算符的优先级
~的优先级最高,其次是<<,>>和>>>,再次是&,然后是^,优先级最低的是|.