一、算数运算符
1、+(正号)
表示一个数字为正值,例如 +1 就是正一,一般可以省略,例如 1 也代表正一。
2、-(负号)
表示一个数字为负值,例如 -1 就是负一。
3、+(加号)
进行算数加运算,例如 1 + 1 = 2 。或者是变量相加。
int a = 10;
int b = 20;
int res = a + b;// res 为30
4、-(减号)
进行算数减运算,例如 1 - 1 = 0 。或者是变量相减。
int a = 10;
int b = 5;
int res = a - b;// res 为5
5、*(乘号)
进行算数乘运算,例如 2 * 2 = 4。或者是变量相乘。
int a = 2;
int b = 3;
int res = a * b;// res 为6
6、/(除号)
进行算数除运算,例如 6 / 3 = 2 。或者是变量相除。这里有一个特殊,这里的除法运算是有两种的,一种是整数除法,一种是浮点数除法。
当两个操作数都是整数类型(如 int
或 long
)时,/
运算符执行整数除法,结果也是一个整数,任何小数部分都会被截断(即结果向零取整)。
int a = 5;
int b = 2;
int res = a / b;//这里使用int变量来存储,如果不报错的话,则说明这里的a / b的结果是整型
System.out.println(res);
这里没有报错,说明这里的 a / b 得到的就是整型数据,最终运行结果为:
这说明这里进行的是整型除法。我们都知道 5 / 2 的结果应该为 2.5 ,但这里是 2 ,就是因为这里的小数部分被截去了。
当至少有一个操作数是浮点数类型(如 float
或 double
)时,/
运算符执行浮点数除法,结果也是一个浮点数。
double num1 = 5.0;
int num2 = 2;
double res = num1 / num2;
System.out.println(res);
这里的运行结果是:
说明这里进行的是浮点数除法。
7、%(取模)
取模就是取余,也就是计算一个数除以另一个数的余数。例如 3 % 2 = 1,也就是 3 除以 2 的余数是 1 。
int a = 10;
int b = 3;
int res = a % b;// res 为1
对于取模的算法是以下的公式:
a % b = a - (int)a / b * b
也就是通过这个 a / b 是整数除法,可以得到商,然后通过使用被除数减去商与除数乘积得到余数。前面的一个 (int) 强制转换是当 a 为小数时使用的。例如:
10 % 3 = 10 - 10 / 3 * 3 = 1。
8、++(自增运算符)
使用于变量自身加一,例如 a++ 就相当于 a = a + 1 ,这会导致变量的值发生改变,正因如此,这个运算符不能对常量使用。
自增运算符以及下面的自减运算符都有一个特点,就是可以前置也可以后置,但这两种方式实现的效果不同。
1)前置++
前置++,就如 ++a ,是先将变量的值自增一,然后再使用变量。也就是先自增,再使用。例如:
int a = 1;
int b = ++a;//这里是先自增,后使用,所以是先 a = a + 1,然后 b = a,所以这里 b 为 2
System.out.println("b = " + b);
System.out.println("a = " + a);
这里是先自增,后使用,所以是先 a = a + 1,然后 b = a,这样b的值就是 2 ,a 也是自增过的,所以 a 也是2,运行结果:
2)后置++
后置++,就如 a++,是先使用变量,然后变量的值再自增一。也就是先使用,再自增。例如:
int a = 1;
int b = a++;//这里是先使用,再自增,所以是 b = a,然后 a = a + 1,这样b的值就是1
System.out.println("b = " + b);
System.out.println("a = " + a);
这里是先使用,再自增,所以是 b = a,然后 a = a + 1,这样b的值就是 1 ,然后 a 是自增一后的,所以 a 的值是2。运行结果:
9、--(自减运算符)
使用于变量自身减一,例如 a-- 就相当于 a = a - 1 ,这会导致变量的值发生改变,正因如此,这个运算符不能对常量使用。
前置 -- 和后置 -- 与前置 ++ 和后置 ++ 的情况类似。
1)前置--
前置--,就如 --a ,是先将变量的值自减一,然后再使用变量。也就是先自减,再使用。例如:
int a = 2;
int b = --a;//这里是先自减,后使用,所以是先 a = a - 1,然后 b = a,所以这里 b 为 1
System.out.println("b = " + b);
System.out.println("a = " + a);
这里是先自减,后使用,所以是先 a = a - 1,然后 b = a,所以这里 b 为 1,a 也是自减后的,所以 a 为1。运行结果:
2)后置--
后置--,就如 a--,是先使用变量,然后变量的值再自减一。也就是先使用,再自减。例如:
int a = 2;
int b = a--;//这里是先使用,后自减,所以是先 b = a,然后 a = a - 1,所以这里 b 为 2
System.out.println("b = " + b);
System.out.println("a = " + a);
这里是先使用,后自减,所以是先 b = a,然后 a = a - 1,所以这里 b 为 2,a 是自减后的,所以 a 是 1 。运行结果:
10、+(字符串连接)
小细节
后置++补充
int i = 1;
i = i++;
System.out.println(i);
运行结果:
这里是因为,对于这里的的内部实现实际上可以具象化成这样:
所以 i 是先变成了 2 ,然后又变成了 1 。
实际上对于一般的后置加加也是这样的原理,也就是会创建一个临时变量来存储原本的值,然后再自增,最后再使用临时变量中原来的值。
对于上面我们描述的先使用后递增,实际上是对于一般情况下的简化,对于上面这个特殊案例,先使用,后递增这个描述就有些错误了。
对于下面这种一般情况:
int i = 1;
a = i++;
我们就可以分析它的底层实现:
这时简化成先使用,后递增,就没有什么错误,但实际上的顺序是不对的。实际上是先递增,然后使用,只不过使用的是临时变量存储的递增之前的值。
前置++补充
对于前置++则没有上面的问题:
int i = 1;
i = ++i;
这里的步骤就像是:
所以这里与我们简化的分析是一致的,先自增,后使用。
二、关系运算符
关系运算符用于比较两个值或表达式,关系运算符的结果都是 boolean 类型的,也就是说关系运算符会返回一个布尔值(true
或false
)。
关系运算符组成的表达式,我们称为关系表达式,例如 a > b 就是一个关系表达式。
关系运算符主要有以下几种:
1、==(等于)
用于比较两个操作数是否相等。如果相等,则返回true
,否则返回false
。
public class Test {
public static void main(String[] args) {
int a = 10;
int b = 30;
System.out.println(a + " == " + b + " is " + (a == b));
}
}
运行结果:
2、!=(不等于)
用于比较两个操作数是否不相等。如果不相等,则返回true
,否则返回false
。
int a = 10;
int b = 30;
System.out.println(a + " != " + b + " is " + (a != b));
运行结果
3、>(大于)
用于判断左操作数是否大于右操作数。如果是,则返回true
,否则返回false
。
int a = 10;
int b = 30;
System.out.println(a + " > " + b + " is " + (a > b));
运行结果:
4、<(小于)
用于判断左操作数是否小于右操作数。如果是,则返回true
,否则返回false
。
int a = 10;
int b = 30;
System.out.println(a + " < " + b + " is " + (a < b));
运行结果:
5、>=(大于或等于)
用于判断左操作数是否大于或等于右操作数。如果是,则返回true
,否则返回false
。
int a = 10;
int b = 30;
System.out.println(a + " >= " + b + " is " + (a >= b));
运行结果:
6、<=(小于或等于)
用于判断左操作数是否小于或等于右操作数。如果是,则返回true
,否则返回false
。
int a = 10;
int b = 30;
System.out.println(a + " <= " + b + " is " + (a <= b));
运行结果:
三、逻辑运算符
逻辑运算符用于布尔值之间的操作,并返回布尔结果(true
或false
)。逻辑运算符主要有以下几种:
1、&(逻辑与)
这里的 & 在逻辑运算符中的话就是逻辑与运算符,在二进制运算符中,就是按位与运算符。这取决于它的操作数的类型:
- 当操作数是布尔类型时,
&
执行逻辑与操作。只有当两个操作数都为true
时,结果才为true
- 当操作数是数值类型时,
&
执行按位与操作。它对两个操作数的每一位执行与操作。
在这里我们介绍的是它作为逻辑与运算符,它的运算规则是:
a & b :当a
和b
同时为true
时,结果为true
,否则为false
。(这里的 a 和 b 可以是 boolean 类型的变量,也可以是结果为 boolean 类型值的表达式,以下的逻辑表达式中的 a 与 b 也是此情形)
public class Test {
public static void main(String[] args) {
boolean a = true;
boolean b = true;
System.out.println("a & b = " + (a & b));
}
}
运行结果:
&(逻辑与)与下面的短路与不同的是,逻辑与在 a 为 false 时,仍会计算后面的 b,我们下面使用一个例子演示一下:
public class Test {
public static void main(String[] args) {
int a = 10;
int b = 20;
if(a < 2 & b++ > 10) {//这里是逻辑与,对于前面的表达式a < 2明显为假,
//但是它仍旧会运算后面的表达式,
//所以b++会运算,所以b会自增,
//所以b变成了21
System.out.println("Hello");
}
System.out.println("a = " + a + "\nb = " + b);
}
}
运行结果:
这里是逻辑与,对于前面的表达式a < 2明显为假,但是它仍旧会运算后面的表达式,所以b++会运算,所以b会自增,所以b变成了21。
2、&&(短路与)
a && b :当a
和b
同时为true
时,结果为true
,否则为false
。如果a
为false
,则不会计算b
(短路特性)。
public class Test {
public static void main(String[] args) {
boolean a = true;
boolean b = true;
System.out.println("a && b = " + (a && b));
}
}
运行结果:
短路与和上面的逻辑与的唯一区别就是如果 a 为 false,则不会再计算 b。因为对于逻辑中的与操作,只要有一个表达式为 false,那么就可以确定整个表达式为 false 了。我们可以通过下面的一个例子进行测试这个特性:
public class Test {
public static void main(String[] args) {
int a = 10;
int b = 20;
if(a < 2 && b++ > 10) {//这里是短路与,对于前面的表达式a < 2明显为假,
//所以后面的表达式不会运算所以b++也不会运算,所以b不会自增,
//所以b还是20
System.out.println("Hello");
}
System.out.println("a = " + a + "\nb = " + b);
}
}
运行结果:
由于这里是短路与,而且对于前面的表达式a < 2明显为假,所以后面的表达式不会运算所以b++也不会运算,所以b不会自增,所以b还是20
开发中我们一般使用 &&(短路与),因为它可以节省性能,效率较高。
3、|(逻辑或)
逻辑或运算符的处境与逻辑与的处境相似:| 在逻辑运算符中的话就是逻辑或运算符,在二进制运算符中,就是按位或运算符。这取决于它的操作数的类型:
- 当操作数是布尔类型时,
|
执行逻辑或操作。只要有一个操作数为true
,结果就为true
。 - 当操作数是整数类型时,
|
执行按位或操作。它对两个操作数的每一位执行或操作。
在这里我们介绍的是它作为逻辑或运算符,它的运算规则是:
a | b :当a
和b
有一个为true
时,结果为true
,否则为false
。
public class Test {
public static void main(String[] args) {
boolean a = true;
boolean b = false;
System.out.println("a | b = " + (a | b));
}
}
运行结果:
|(逻辑或)与下面的短路或不同的是,逻辑或在 a 为 true 时,仍会计算后面的 b,我们下面使用一个例子演示一下:
public class Test {
public static void main(String[] args) {
int a = 10;
int b = 20;
if(a > 0 | b++ > 10) {//这里是逻辑或,对于前面的表达式a > 0明显为真,
//但是它仍旧会计算后面的表达式,
//所以b++也会运算,所以b就会自增,
//所以b就变为了21
System.out.println("Hello");//而且因为这里的总表达式为真,所以会打印Hello
}
System.out.println("a = " + a + "\nb = " + b);
}
}
运行结果:
这里是逻辑或,对于前面的表达式a > 0明显为真,但是它仍旧会计算后面的表达式,所以b++也会运算,所以b就会自增,所以b就变为了21
4、||(短路或)
a || b :当a
和b
有一个为true
时,结果为true
,否则为false
。如果a
为true
,则不会计算b
(短路特性)。
public class Test {
public static void main(String[] args) {
boolean a = true;
boolean b = false;
System.out.println("a || b = " + (a || b));
}
}
运行结果:
短路或和上面的逻辑或的唯一区别就是如果 a 为 true,则不会再计算 b。因为对于逻辑中的或操作,只要有一个表达式为 true,那么就可以确定整个表达式为 true 了。我们可以通过下面的一个例子进行测试这个特性:
public class Test {
public static void main(String[] args) {
int a = 10;
int b = 20;
if(a > 0 || b++ > 10) {//这里是短路或,对于前面的表达式a > 0明显为真,
//所以后面的表达式不会运算,
//所以b++不会运算,所以b不会自增,
//所以b还是20
System.out.println("Hello");//而且因为这里的总表达式为真,所以会打印Hello
}
System.out.println("a = " + a + "\nb = " + b);
}
}
运行结果:
这里是短路或,对于前面的表达式a > 0明显为真,所以后面的表达式不会运算,所以b++不会运算,所以b不会自增,所以b还是20
开发中我们一般使用 ||(短路或),因为它可以节省性能,效率较高。
5、!(逻辑非)
!a :取a
的反值。如果a
为true
,结果为false
;如果a
为false
,结果为true
。
public class Test {
public static void main(String[] args) {
boolean a = true;
System.out.println("!a = " + (!a));
}
}
运行结果:
6、^(逻辑异或)
^ 在逻辑运算符中的话就是逻辑或异或算符,在二进制运算符中,就是按位异或运算符。这取决于它的操作数的类型:
- 当操作数是布尔类型时,^ 执行逻辑或操作。只要一个操作数为
true
,另一操作数是false
,结果为true
,否则为false
。也就是相同为false
,相异为true
。 - 当操作数是整数类型时,^ 执行按位或操作。它对两个操作数的每一位执行或操作。
在这里我们介绍的是它作为逻辑异或运算符,它的运算规则是:
如果两个布尔操作数不同(即一个为true
,另一个为false
),结果为true
;如果两个操作数相同,结果为false
。
public class Test {
public static void main(String[] args) {
boolean a = true;
boolean b = true;
System.out.println("a ^ b = " + (a ^ b));
}
}
运行结果:
四、位运算符
位运算符都是在二进制补码的基础上进行操作的。
1、&(按位与)
1)介绍
对两个操作数的对应位执行与操作。仅当对应位均为1时,结果位才为1,否则为0。
假设某两个数的二进制补码某同一位上的数字为 p 和 q :
p | q | p & q |
1 | 1 | 1 |
0 | 1 | 0 |
1 | 0 | 0 |
0 | 0 | 0 |
例如:
public class Test {
public static void main(String[] args) {
int a = -7;
int b = 5;
int res = a & b;
System.out.println("-7 & 5 = " + res);
}
}
运行结果:
下面进行具体分析:
最终结果为 1 ,与运行结果一致。
2)特点
任何数按位与 0 的结果都是 0 ,任何数按位与其本身的结果都是其本身。
2、|(按位或)
1)介绍
对两个操作数的对应位执行或操作。只要对应位有一个为1,结果位就为1,否则为0。
假设某两个数的二进制补码某同一位上的数字为 p 和 q :
p | q | p | q |
1 | 1 | 1 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
例如:
public class Test {
public static void main(String[] args) {
int a = -7;
int b = 5;
int res = a | b;
System.out.println("-7 | 5 = " + res);
}
}
运行结果:
下面进行详细分析:
上面已经求出 -7 的补码,这里不再赘述。
与运行结果一致。
2)特点
任何数按位或 0 结果都是这个数本身。
3、^(按位异或)
1)介绍
对两个操作数的对应位执行异或操作。当对应位不同(一个为1,一个为0)时,结果位为1,否则为0。
假设某两个数的二进制补码某同一位上的数字为 p 和 q :
p | q | p ^ q |
1 | 1 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
例如:
public class Test {
public static void main(String[] args) {
int a = -7;
int b = 5;
int res = a ^ b;
System.out.println("-7 ^ 5 = " + res);
}
}
运行结果:
2)特点
任何数按位异或自身的结果都是 0 ,任何数按位异或 0 都是其本身。
按位异或运算满足交换律:
a ^ b ^ c = a ^ c ^ b = b ^ c ^ a = b ^ a ^ c = c ^ a ^ b = c ^ b ^ a
例如:
public class Test {
public static void main(String[] args) {
int a = 1 ^ 2 ^ 3;
int b = 1 ^ 3 ^ 2;
int c = 2 ^ 1 ^ 3;
int d = 2 ^ 3 ^ 1;
int e = 3 ^ 1 ^ 2;
int f = 3 ^ 2 ^ 1;
System.out.println("1 ^ 2 ^ 3 = " + a);
System.out.println("1 ^ 3 ^ 2 = " + a);
System.out.println("2 ^ 1 ^ 3 = " + a);
System.out.println("2 ^ 3 ^ 1 = " + a);
System.out.println("3 ^ 1 ^ 2 = " + a);
System.out.println("3 ^ 2 ^ 1 = " + a);
}
}
运行结果:
一个很神奇的题目做法:
不使用临时变量,交换两个变量的值。
public class Test {
public static void main(String[] args) {
int a = 3;
int b = 5;
System.out.println("交换前");
System.out.println("a = " + a + "\nb = " + b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
System.out.println("交换后");
System.out.println("a = " + a + "\nb = " + b);
}
}
运行结果:
核心代码就是:
a = a ^ b;
b = a ^ b;
a = a ^ b;
下面进行详细介绍:
4、~(按位取反)
1)介绍
对操作数的每个位(包括符号位)执行取反操作,即0变1,1变0。
假设某一个数的二进制补码某一位上的数字为 p :
p | ~p |
1 | 0 |
0 | 1 |
例如:
public class Test {
public static void main(String[] args) {
int a = -7;
int res = ~a;
System.out.println("~a = " + res);
}
}
运行结果:
下面进行详细介绍:
与运行结果一致。
2)特点
我们可以直接对一个数使用取反加一来求一个数字的相反数:
int a = 2;
int b = ~a + 1;
System.out.println(a);
System.out.println(b);
运行结果:
我们可以看一下图解:
具体原因可以看我之前的文章《Java——二进制原码、反码和补码_原码反码补码-CSDN博客》。
5、<<(左移)
1)介绍
将操作数的所有位向左移动指定的位数,右边补0。左移n位相当于乘以2的n次方。
例如:
public class Test {
public static void main(String[] args) {
int a = 5;
int res = a << 2;//左移两位
System.out.println("a << 2 = " + res);
}
}
运行结果:
下面进行详细介绍:
左移 2 位就相当于乘以 2 的 2 次方,也就是乘以 4 ,5 乘以 4 为 20,与我们运行结果和分析是一致的。
又如:
public class Test {
public static void main(String[] args) {
int a = -7;
int res = a << 2;//左移两位
System.out.println("-7 << 2 = " + res);
}
}
运行结果:
下面进行详细分析:
左移 2 位相当于乘 2 的 2 次方,也就是乘 4 ,-7 乘 4 为 -28 。最终结果为 -28,与运行结果一致。
2)特别补充
左移是会连带符号位一起移动的,也就是说无论是数值位还是符号位,都要左移。
我们可以通过下面的例子进行验证:
public class Test {
public static void main(String[] args) {
int a = -2147483647;
//11111111 11111111 11111111 11111111 -2147483647 的原码
//10000000 00000000 00000000 00000001 -2147483647 的补码
//假设 1、不移符号位 10000000 00000000 00000000 00000010补码
// 11111111 11111111 11111111 11111110原码
// 结果为 -2147483646
//假设 2、移动符号位 00000000 00000000 00000000 00000010
// 结果为 2
System.out.println("结果为 " + (a << 1));
}
}
最终运行结果为:
所以说实际情况是我们的假设 2 的情况,也就是左移时符号位也会左移。
6、>>(算数右移)
将操作数的所有位向右移动指定的位数,左边补符号位(即正数补0,负数补1)。右移n位相当于除以2的n次方(向下取整,就是取整较小的数)。
例如:
public class Test {
public static void main(String[] args) {
int a = 5;
int res = a >> 2;//算数右移两位
System.out.println("5 >> 2 = " + res);
}
}
运行结果:
下面进行详细分析:
算数右移 2 位相当于除以 2 的 2 次方,也就是除以 4 ,5 除以 4 为 1.25 ,向下取整,取较小的数,为 1,所以结果为 1,与运行结果一致。
又如:
public class Test {
public static void main(String[] args) {
int a = -7;
int res = a >> 2;//算数右移两位
System.out.println("-7 >> 2 = " + res);
}
}
运行结果:
下面进行详细分析:
算数右移 2 位相当于除以 2 的 2 次方,也就是除以 4 ,-7 除以 4 为 -1.75 ,向下取整,取较小的数,为 -2( -2 小于 -1 ),所以结果为 -2,与运行结果一致。
7、>>>(逻辑右移 / 无符号右移)
将操作数的所有位向右移动指定的位数,左边补 0。逻辑右移忽略符号位,对正负数都用 0 填充左边空位。
例如:
public class Test {
public static void main(String[] args) {
int a = 5;
int res = a >>> 2;//逻辑右移两位
System.out.println("5 >>> 2 = " + res);
}
}
运行结果:
这里的分析与运行结果一致。对于正数算数右移和逻辑右移的结果是一样的,因为在算数右移中,正数的左边也是补0,在逻辑右移中,正数的右边同样是补0。
又如:
public class Test {
public static void main(String[] args) {
int a = -7;
int res = a >>> 2;//逻辑右移两位
System.out.println("-7 >>> 2 = " + res);
}
}
运行结果:
下面进行详细分析:
最终结果与运行结果一致。
五、赋值运算符
在Java中,赋值运算符左侧必须是左值(L-value),右侧可以是右值(R-value)或左值。
左值(L-value,Left Value 或 Locator Value):
- 左值是指可以出现在赋值操作符左边的表达式。它表示一个存储位置,可以被赋值。
- 左值是可以被取地址的(即它们有存储位置)。
- 在Java中,左值通常是变量或对象属性。
int x = 10; // x 是左值,可以被赋值
右值(R-value,Right Value 或 Read value):
- 右值是指出现在赋值操作符右边的表达式。它表示一个数据值,可以被读取。
- 右值不一定要有存储位置,可以是常量、字面值或者表达式的结果。
- 右值可以是变量的值。
int y = x; // x 是左值,但在这里作为右值使用,表示 x 的值
int z = 5; // 5 是右值
1、=(简单赋值运算符)
用于将右侧的值赋给左侧的变量。
int a = 5; // 将值 5 赋给变量 a
2、+=(加法赋值运算符)
将右侧的值加到左侧变量的当前值,并将结果赋给左侧变量。
int a = 5;
a += 3; // 等同于 a = a + 3,结果 a 为 8
3、-=(减法赋值运算符)
将右侧的值从左侧变量的当前值中减去,并将结果赋给左侧变量。
int a = 5;
a -= 3; // 等同于 a = a - 3,结果 a 为 2
4、*=(乘法赋值运算符)
将左侧变量的当前值与右侧的值相乘,并将结果赋给左侧变量。
int a = 5;
a *= 3; // 等同于 a = a * 3,结果 a 为 15
5、/=(除法赋值运算符)
将左侧变量的当前值除以右侧的值,并将结果赋给左侧变量。
int a = 6;
a /= 3; // 等同于 a = a / 3,结果 a 为 2
6、%=(取模赋值运算符)
将左侧变量的当前值与右侧的值取模运算,并将结果赋给左侧变量。
int a = 5;
a %= 3; // 等同于 a = a % 3,结果 a 为 2
7、&=(按位与赋值运算符)
将左侧变量的当前值与右侧的值按位与运算,并将结果赋给左侧变量。
int a = 5; // 二进制补码:00000000 00000000 00000000 00000101
int b = 3; // 二进制补码:00000000 00000000 00000000 00000011
a &= b; // 等同于 a = a & b,结果 a 为 1(二进制补码:00000000 00000000 00000000 00000001)
8、|=(按位或赋值运算符)
将左侧变量的当前值与右侧的值按位或运算,并将结果赋给左侧变量。
int a = 5; // 二进制补码:00000000 00000000 00000000 00000101
int b = 3; // 二进制补码:00000000 00000000 00000000 00000011
a |= b; // 等同于 a = a | b,结果 a 为 7(二进制:00000000 00000000 00000000 00000111)
9、^=(按位异或赋值运算符)
将左侧变量的当前值与右侧的值按位异或运算,并将结果赋给左侧变量。
int a = 5; // 二进制:00000000 00000000 00000000 00000101
int b = 3; // 二进制:00000000 00000000 00000000 00000011
a ^= b; // 等同于 a = a ^ b,结果 a 为 6(二进制:00000000 00000000 00000000 00000110)
10、<<=(左移赋值运算符)
将左侧变量的当前值左移指定的位数,并将结果赋给左侧变量。
int a = 5; // 二进制:0101
a <<= 1; // 等同于 a = a << 1,结果 a 为 10(二进制:1010)
11、>>=(算数右移赋值运算符)
将左侧变量的当前值算数右移(右移时左侧用符号位填充)指定的位数,并将结果赋给左侧变量。
int a = 5; // 二进制:0101
a >>= 1; // 等同于 a = a >> 1,结果 a 为 2(二进制:0010)
12、>>>=(逻辑右移赋值运算符)
将左侧变量的当前值无符号逻辑右移(右移时左侧用零填充)指定的位数,并将结果赋给左侧变量。
int a = -5; // 二进制:11111111111111111111111111111011
a >>>= 1; // 等同于 a = a >>> 1,结果 a 为 2147483645(二进制:01111111111111111111111111111101)
补充:
复合赋值运算符会自动进行类型转换。
就如:
byte num1 = 1;
num1 += 2;
我们说这里的 num1 += 2;相当于 num1 = num1 + 2;但是如果是真的相当于这里的:
num1 = num1 + 2;
那这里的 num1 的类型是 byte ,它在计算时会提升至 int 类型,这里后面的部分 num1 + 2 得到的结果应当是 int 类型,如果直接赋值给一个 byte 类型的变量,理应会报错,但这里没有,就是因为这里的复合赋值运算符不仅仅是等价于这个语句,而且复合赋值运算符还会自动进行类型转换,它实际上应当相当于:
num1 = (byte)(num1 + 2);
实际上对于我们之前说的 i++ 相当于 i = i + 1 与这里是相似的,它应当相当于:
i = (type)(i + 1);
六、其他运算符
1、? :(三元运算符 / 条件运算符)
介绍:
用于基于一个布尔表达式的结果选择值。这个运算符是一种简洁的if-else
表达形式,可以大大简化代码,提高可读性。三元运算符的语法如下:
conditionExpression ? expression1 : expression2;
conditionExpression 是条件表达式,当条件表达式的结果为 true 时,expression1 的值就是这个三元表达式的值,当表达式的结果为 false 时,expression2 的值就是这个三元表达式的值。
- conditionExpression 是一个布尔表达式。
- expression1 是当 conditionExpression 为
true
时的结果。 - expression2 是当 conditionExpression 为
false
时的结果。
public class Test {
public static void main(String[] args) {
int a = 10;
int b = 20;
int max = (a > b) ? a : b;//利用三元运算符求两个数的最大值
System.out.println("The maximum number between " + a + " and " + b + " is " + max);
}
}
运行结果:
补充:
public class Test {
public static void main(String[] args) {
int a = 10;
int b = 20;
int result = (a > b) ? a++ : b++;
System.out.println("a = " + a + "\nb = " + b + "\nresult = " + result);
}
}
运行结果:
这里的 a > b 为 false ,所以执行表达式二,即 b++ ,这时因为是后置++,所以会先使用,后自增,所以这里的 result 被赋值为 20 ,然后 b 自增,b 就变成了 21 。这里的表达式一,即 a++ ,并没有执行,所以 a 没有自增,所以 a 还是 10。
三元运算符可以嵌套:
public class Test {
public static void main(String[] args) {
int a = 10;
int b = 20;
int c = 30;
int max = (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c);
//利用嵌套三元运算符实现求三个数的最大值
System.out.println(max);
}
}
运行结果:
2、instanceof 运算符
instanceof
运算符是Java中用于测试对象是否是某个特定类或其子类的实例的关键字。它在运行时进行类型检查,返回一个布尔值(true
或 false
),用于确保对象的类型安全性。instanceof
运算符的基本语法如下:
object instanceof ClassName;
object
是需要进行类型检查的对象。ClassName
是你希望检查的类或接口。
示例:
public class Test {
public static void main(String[] args) {
boolean res = "Hello" instanceof String;
System.out.println(res);
}
}
运行结果:
字符串 "Hello"
实际上是 String
类的一个对象,因此 instanceof
运算符会返回 true
。
"Hello"
是一个 String
对象。instanceof
运算符用于检查 "Hello"
是否是 String
类的一个实例。由于 "Hello"
确实是 String
类的一个实例,所以 res
的值为 true
。System.out.println(res)
将输出 true
。
运算符的优先级
运算符有不同的优先级,优先级就是表达式中的运算顺序。就像我们在计算 1 + 2 * 3 时总是要先算乘法一样,在这个表达式中,乘法的优先级较高。
类别 | 操作符 | 关联性 |
---|---|---|
后缀 | () [] . (点操作符) | 从左到右 |
一元 | expr++ expr-- | 从左到右 |
一元 | ++expr --expr + - ~ ! | 从右到左 |
乘性 | * /% | 从左到右 |
加性 | + - | 从左到右 |
移位 | >> >>> << | 从左到右 |
关系 | > >= < <= instanceof | 从左到右 |
相等 | == != | 从左到右 |
按位与 | & | 从左到右 |
按位异或 | ^ | 从左到右 |
按位或 | | | 从左到右 |
逻辑与 | && | 从左到右 |
逻辑或 | | | | 从左到右 |
条件 | ?: | 从右到左 |
赋值 | = + = - = * = / =%= >> = << =&= ^ = | = | 从右到左 |
逗号 | , | 从左到右 |