先说结论:
位移运算符:
i<<N 运算符把i 的所有位向左移N指定的位数,低位用0代替。
i>>N就是运算符把 i的所有位向右移 N指定的位数。i的符号位被用来填充右移后左边空出来的位。向右移出的位被丢弃。
i>>>N就是运算符把i 的各个位向右移 N位数。右移后左边空出的位用零来填充。移出右边的位被丢弃。
位运算符:
A&B表示二进制同位都是1,结果才是1,否则为0
A|B表示二进制同位只要有一位是1,结果就是1,否则为0
A^B表示二进制同位互为相反数,结果就是1,否则为0
~A表示二进制位为0,结果是1,如果位为1,结果是0
1.位移运算符>> , << , >>>
例如HashMap源码的时候,在计算hash值的时候,就使用到了位移运算符,代码如下:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
首先要了解10进制的正数和复制二进制怎么转中,需要对源码、反码、补码有所了解;先上代码:
@Test
public void test2() {
//转2进制
Function<Byte,String> function=(i)-> Integer.toBinaryString((i & 0xFF) + 0x100).substring(1) ;
System.out.println("1的2进制是:"+function.apply((byte) 1));
System.out.println("-1的2进制是:"+function.apply((byte) -1));
}
输出的结果是 1的2进制是:0000 0001
-1的2进制是: 1111 1111
二进制的最高位为符号位,1 表示负数,0 表示整数,其余位表示数的绝对值。
负数2进制其实很容易理解:就是正数的源码取反再+1
例如 byte i =-1
i的正数源码: 0000 0001
对源码取反码:1111 1110
再加1(补码): 1111 1111
1.1左位移运算符 <<
下面我用以任意一个10进制的int数据 为例进行解析:
@Test
public void test2() {
//转2进制
Function<Integer,String> function=(i)-> Integer.toBinaryString(i) ;
Consumer<Integer> leftTo2=(i)->{
System.out.println(i+"的2进制是:"+function.apply(i));
System.out.println(i+"向左位移是:"+function.apply((i<<2)));
} ;
leftTo2.accept(1);
leftTo2.accept(-1);
}
输出的结果是 1的2进制是: 0000 0000 0000 0000 0000 0000 0000 0001
1向左位移是:0000 0000 0000 0000 0000 0000 0000 0100
-1的2进制是: 1111 1111 1111 1111 1111 1111 1111 1111
-1i向左位移是:1111 1111 1111 1111 1111 1111 1111 1100
总结:i<<N 运算符把i 的所有位向左移N指定的位数,低位用0代替。
1.2.右位移运算符 >>
下面我用以任意一个10进制的int数据为例进行解析:
@Test
public void test2() {
//转2进制
Function<Integer,String> function=(i)-> Integer.toBinaryString(i) ;
Consumer<Integer> leftTo2=(i)->{
System.out.println(i+"的2进制是:"+function.apply(i));
System.out.println(i+"向右位移是:"+function.apply((i>>2)));
} ;
leftTo2.accept(100);
leftTo2.accept(-100);
}
输出的结果是 100的2进制是: 0000 0000 0000 0000 0000 0000 0110 0100
100向右位移是: 0000 0000 0000 0000 0000 0000 0001 1001
-100的2进制是:1111 1111 1111 1111 1111 1111 1001 1100
-100向右位移是:1111 1111 1111 1111 1111 1111 1110 0111
总结:i>>N就是运算符把 i的所有位向右移 N指定的位数。i的符号位被用来填充右移后左边空出来的位。向右移出的位被丢弃。
1.3.无符号右移运算符:>>>
下面我用以任意一个10进制的byte数据 byte i = 100 为例进行解析:
@Test
public void test2() {
//转2进制
Function<Byte,String> function=(i)-> Integer.toBinaryString((i & 0xFF) + 0x100).substring(1) ;
byte y =100 ;
System.out.println(y+"的2进制是:"+function.apply(y));
System.out.println(y+"无符号右移是:"+function.apply((byte) (y>>>2)));
byte i =-6 ;
System.out.println(i+"的2进制是:"+function.apply(i));
System.out.println(i+"无符号右移是:"+function.apply((byte) (i>>>2)));
}
输出的结果是 1的2进制是: 0000 0000 0000 0000 0000 0000 0000 0001
1无符号位移2位是: 0000 0000 0000 0000 0000 0000 0000 0000
-1的2进制是: 1111 1111 1111 1111 1111 1111 1111 1111
-1无符号位移2位是: 0011 1111 1111 1111 1111 1111 1111 1111
总结:i>>>N就是运算符把i 的各个位向右移 N位数。右移后左边空出的位用零来填充。移出右边的位被丢弃。
2.位运算符号'&','|','~','^'
位运算符针对二进制,它包括了:“与”、“非”、“或”、“异或”。
2.1'&'与运算符
@Test
public void test2() {
//转2进制
Function<Integer,String> function=(i)-> Integer.toBinaryString(i) ;
BiConsumer<Integer,Integer> leftTo2=(a,b)->{
System.out.println(a+"的二进制:"+function.apply(a));
System.out.println(b+"的二进制:"+function.apply(b));
System.out.println(a+"&"+b+":"+function.apply(a&b));
} ;
leftTo2.accept(100,50);
}
输出结果
100的二进制:0000 0000 0000 0000 0000 0000 0110 0100
50的二进制: 0000 0000 0000 0000 0000 0000 0011 0010
100&50: 0000 0000 0000 0000 0000 0000 0010 0000
结论 A&B表示二进制同位都是1,结果才是1,否则为0
2.2'|'与运算符
代码同2.1;吧&替换为|。
100的二进制:0000 0000 0000 0000 0000 0000 0110 0100
50的二进制: 0000 0000 0000 0000 0000 0000 0011 0010
100|50: 0000 0000 0000 0000 0000 0000 0111 0110
结论 A|B表示二进制同位只要有一位是1,结果就是1,否则为0
2.3'^'异或运算符
代码同2.1;吧&替换为^。
100的二进制:0000 0000 0000 0000 0000 0000 0110 0100
50的二进制: 0000 0000 0000 0000 0000 0000 0011 0010
100^50: 0000 0000 0000 0000 0000 0000 0101 0110
结论 A^B表示二进制同位互为相反数,结果就是1,否则为0
2.4'~'非运算符
100的二进制:0000 0000 0000 0000 0000 0000 0110 0100
~50的二进制:1111 1111 1111 1111 1111 1111 1001 1011
结论 ~A表示二进制位为0,结果是1,如果位为1,结果是0
3.算术运算符'+','-','*','/','%'
+,-,*,/绝大部分人都知道是加减乘除,需要注意的点就是运算中注意精度损失 ;%是取模运算,也就是取余数。
4.比较运算符'>','<','<=','>=','==','!='
99%程序员知道怎么使用,这里不再讨论。
5.逻辑运算符号'||','&&','!','',''.
“短路”:逻辑运算针对的BOOLEAN运算 在逻辑运算符当中不得不讲“短路”问题,例如 false&&ttrue 如果运算左边为false,就不会再运算右边。
在面试中常见问题:&&和&的区别:表面是‘短路’区别;深层次原因是&针对的是位运算,必须对2边进行运行,详细见2.1
6.一元运算符'!','++','--','-','~'
概述:因操作数是一个,故称为一元运算
运算符 | 含义 |
- | 改变数值的符号,取反。 |
~ | 属于位运算符,详见位运算符 |
++ | 自加1 |
-- | 自减1 |
! | 逻辑运算符 |
面试中常见问题: i++和++i的区别:
int b =++i 先自加1,再赋值。 i=i+1 ; b=i ;
int b=i++ 先赋值,再加1。 b=i ; i=i+1 ;
7、赋值运算符
赋值运算符是指为变量或常量指定数值的符号。如可以使用 “=” 将右边的表达式结果赋给左边的操作数。
Java 支持的常用赋值运算符,如下表所示: