算术运算符
加 减 乘 除 取余
取模运算,余数的符号跟被除数符号相同
public static void main(String[] args) {
System.out.println(10 / 4); // 2 注意除法计算结果,因为都为整数,所以结果2.5会取整
System.out.println(10.0 / 4); //2.5
double d = 10 / 4;
System.out.println(d); // 2.0
}
@Test
public void test_9() {
System.out.println(5 % 2); //1
System.out.println(5.0 % 2); //1.0 求余运算也会类型提升
System.out.println(-5 % 2); //-1 结果的符号和被除数的符号一致
//公式: a%b = a-a/b *b =》 -5%2 = -5-(-5)/2*2 = -5 -(-2)*2 = -5 + 4 = -1
System.out.println(5 % -2); //1
System.out.println(-5 % -2); //-1
}
public class Test17 {
public static void main(String args[]) {
int x = -5;
int y = -12;
System.out.println(y % x); // -2 取模运算,余数的符号跟被除数符号相同
//无论是正数还是负数,在取余运算时都有:
//被除数=商×除数+余数,所以-12=2×(-5)+(-2),-12是被除数,-5是除数,2是商,余数是-2。
}
}
自增自减
n++ ,++n,n—,—n
@Test
public void test_9() {
int a = 5;
int b = a++; //先赋值后自增自减
System.out.println(a); //6
System.out.println(b); //5
int a1 = 5;
System.out.println(a1++); //5
}
@Test
public void test_9() {
int a = 5;
int b = ++a; //先自增自减后赋值
System.out.println(a); //6
System.out.println(b); //6
int a1 = 5;
System.out.println(++a1); //6
}
public static void main(String[] args) {
int i = 1;
i = i++; // temp =i; i=i+1; i=temp
System.out.println(i); //1
int j = 1;
j = ++j; // j=j+1; temp=j; j=temp
System.out.println(j);//2
}
//https://www.bilibili.com/video/BV1xt411S7xy
public static void main(String[] args) {
int i = 1;
i = i++; // i =1
int j = i++; //j=1, i=2
int k = i + ++i * i++; // 2 + 3 * 3
System.out.println("i=" + i);
System.out.println("j=" + j);
System.out.println("k=" + k);
}
关系运算符
大于> 大于等于>= 小于< 小于等于<= 等于== 不等于!=
关系运算符的运行结果是布尔值。
逻辑运算符
&& 与 ||或 !非
操作数只能是布尔值。
& (和 | 是位运算,可以进行逻辑运算。
&& 短路与, & 逻辑与。
区别:逻辑运算符有短路效果,位运算符不具有短路效果。
- 单个的逻辑运算符会将左右两个表达式都进行运算得出布尔值,再进行运算。
- ‘短路与’&& 若左边表达式为false则不会对右边的表达式进行判断,因为结果必为false;
- ‘短路或’|| 若左边表达式结果为true则不会对右边的表达式进行判断,因为结果必为true。
public class Test13 {
private static int j = 0;
private static Boolean methodB(int k) {
j += k;
return true;
}
public static void methodA(int i) {
boolean b;
// 对于boolean值,按位操作与逻辑操作有相同的结果,但是不会发生“短路”。
b = i < 10 | methodB(4); //不会编译错误,这里是给b赋值,而不是访问b
b = i < 10 || methodB(8); //短路或 || 如果结果确定,不继续计算
}
public static void main(String args[]) {
methodA(0);
System.out.println(j); //4
}
}
扩展赋值运算符
+= -+ = /= %=
例如:a+=b ==> a = a +b
*注意:扩展运算法会有隐式强转
@Test
public void test_9() {
short n = 5; // 因为5在short的范围内,不会报错
n = n + 3; //编译报错, int转short
System.out.println(n);
}
@Test
public void test_9() {
short n = 5; // 因为5在short的范围内,不会报错
n += 3; //这里会有一个隐式强转 (short)(n+3)
System.out.println(n);
}
条件运算符
表达式一 ? 表达式二 : 表达式三
表达式一运算的结果是布尔值
表达式二和表达式三要求 类型相符
表达式一的结果为true,就执行表达式二
表达式一的结果为false,就执行表达式三
@Test
public void test_9() {
Object object = true ? "" : new Object(); //其实这样也可以
double v = true ? 2 : 2.2;
//int v2 = true ? 2 : 2.2; //编译报错,2.2不能自动转为int
}
位运算符
与& 或 | 非~ 异或 ^ 左移<< 右移>> 无符号右移>>>
按位运算符
- & 按位与 规则:两个同为1的时候才为1。
- | 按位或 规则:两个只要有一个为1就为1。
- ^ 按位异或 规则:如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。
- ~ 取反 规则:1 变0, 0变1 (单目运算符)
右移 规则:让操作数除以2的n次幂,n就是移动的位数,左边空出的位置用符号位的值补全
- << 左移 规则:让操作数乘以2的n次幂,n就是移动的位数
无符号右移 规则:让操作数除以2的n次幂,n就是移动的位数, 左边空出的位置用0补齐
在进行位运算的时候要把数据转换成二进制位,并且全部都是二进制的补码形式。
~ 取反
对3进行取反位运算:~3
3是正数,原码、反码、补码是一样的。
3的补码: 0b00000000 00000000 00000000 00000011
取反~3: 0b11111111 11111111 11111111 11111100 (此时是补码,补码是原码取反加1来的,现在是减1取反)
求原码-1:0b11111111 11111111 11111111 11111011 (求原码取反的时候,符号位不需要取反)
求原码取反:0b10000000 00000000 00000000 00000100 (此时是原码) -4 给人类显示的是原码
@Test
public void test_8() {
System.out.println(~3); //-4
}
^ 按位异或
一个数据对相同的数据异或两次其值不变。
a^b^b = a
@Test
public void test_8() {
int a =3;
int b =4;
System.out.println(a^b^b); //3
}
通过异或实现两个变量交换,不需要第三个变量
@Test
public void test_8() {
//一个数据对相同的数据异或两次其值不变。
/*
a = a ^ b;
b = a ^ b; => a^b^b的结果就是a, 此时把a的值赋给b
a = a ^ b; => a^b^a(因为现在的b其实是a)的结果就是b, 此时把b的值赋给a
=> a^b^a^b^b => a^a^b => b
*/
int i = 10;
int j = 20;
i = i ^ j;
j = i ^ j;
i = i ^ j;
System.out.println(i); //20
System.out.println(j); //10
}
>> 和 <<
往左移动两位,右边就空出两位,左边移动的两位就被挤掉了,右边空出的两位用0补全;
往右移动两位,左边就空出两位,右边的两位就被挤掉了,左边空出的两位用符号位的值填充(符号位是1就填充1,是0就填充0);
@Test
public void test_9() {
int i = 3<<4; // 3*2^4
System.out.println(i); //48
int j = 3>>4; // 3/2^4
System.out.println(j); //0
int k = 35>>4; // 35/2^4
System.out.println(k); //2
int l = -35>>4; // 35/2^4
System.out.println(l); //-3
}
-35的原码:10000000 00000000 00000000 00100011
-35的反码:11111111 11111111 11111111 11011100
-35的补码:11111111 11111111 11111111 11011101
-35的补码右移4位:1111 11111111 11111111 11111111 1101
减1: 1111 11111111 11111111 11111111 1100
取反:1000 00000000 00000000 00000000 0011
>>> 无符号右移
往右移动两位,左边就空出两位,右边的两位就被挤掉了,左边空出的两位用0填充。
对于正数,>> 和 >>>的结果是一样的。
对于负数,>> 和 >>>的结果是不一样的, >>>会变为正数。
public void test_9() {
int k = 35>>>4; // 35/2^4
System.out.println(k); //2
int l = -35>>>4; // 35/2^4
System.out.println(l); //268435453
System.out.println(0b00001111111111111111111111111101); //268435453
}
-35的原码:10000000 00000000 00000000 00100011
-35的反码:11111111 11111111 11111111 11011100
-35的补码:11111111 11111111 11111111 11011101
-35的补码右移4位:0000 11111111 11111111 11111111 1101 (此时是补码,但是是正数,原码和补码一样)