【浅尝Java】运算符全介绍(含除法取模运算各情况分析、位运算与移位运算分析、逻辑与条件运算符)
🍞自我激励:每天努力一点点,技术变化看得见
文章目录
- 为什么要有运算符
- 算术运算符
- 四则运算符(+ - * / %)
- 增量运算符(+= -= *= /= %=)
- 自增/自减运算符(++ --)
- 关系运算符
- 逻辑运算符
- 逻辑与 &&
- 逻辑或 ||
- 逻辑非 !
- 短路求值
- &&与||的短路求值规则
- 避免短路求值
- 位运算符
- 按位与 &
- 按位或 |
- 按位取反 ~
- 按位异或 ^
- 移位运算符
- 左移运算符 <<
- 右移运算符 >>
- 无符号右移 >>>
- 条件运算符
为什么要有运算符
计算机最基本的用途之一就是执行数学运算,为完成数学运算,就需要运算符的存在。
package demo1;public class Test {public static void main(String[] args) {int num1 = 1;int num2 = 2;if(num2 > num1) {System.out.println("num2 数值更大!");}else {System.out.println("num1 数值更大!");}System.out.println("num1 - num2 = " + (num1 - num2));System.out.println("num1 - num2 = " + (num1 + num2));}
}
上述程序中的<
、+
、-
就是运算符。对于操作数进行操作的符号成为运算符,不同运算符操作的含义不同。
作为一门计算机语言,Java也提供了一套丰富的运算符来操纵变量,以完成各类运算操作。Java的运算符可分为:算术运算符、关系运算符、逻辑运算符、位运算符、移位运算符、条件运算符等,下文将对以上运算符做出介绍。
算术运算符
四则运算符(+ - * / %)
四则运算符包含:加法运算符(+
)、减法运算符(-
)、乘法运算符(*
)、除法运算符(/
)、取模运算符(%
),合计5种。下面给出示例代码:
package demo1;public class Test {public static void main(String[] args) {int num1 = 20;int num2 = 15;// 加法运算符System.out.println(num1 + num2);// 减法运算符System.out.println(num1 - num2);// 乘法运算符System.out.println(num1 * num2);// 除法运算符System.out.println(num1 / num2);// 取模运算符System.out.println(num1 % num2);}
}
从上述代码可知,这5种运算符均是二元运算符,即使用时必须要有左右两个操作数。
加法、减法、乘法计算没有什么特别地方,但上面除法的结果与正确答案不同,取模运算又什么呢?下方对他们进行解释,并给出注意事项。
Java中的除法运算与算术计算结果有所区别,我们从下方代码及其结果来总结出对应结论:
public class Main {public static void main(String[] args) {System.out.println(9 / 2);System.out.println((float)9 / 2);System.out.println(9 / (float)2);System.out.println((float)(9 / 2));}
}
综上可知,除法运算时,int类型除int类型的结果为int类型,结果向下取整,不会四舍五入;若左右操作数中,有至少一个为float或double类型,则可准确计算出数值。
接下来,我们再看一段代码,并对%(取模)运算进行解释:
public class Main {public static void main(String[] args) {System.out.println(10 % 3);System.out.println(10 % -3);System.out.println(-10 % 3);System.out.println(-10 % -3);}
}
分析算是10 ÷ 3 = 3 ... 1
,其余数为1。模运算的结果就是余数,由于10除3的结果为1,固10%3的结果为1,且模运算结果的操作符与左侧操作数一致。
若你此前学过C/C++语言,则会知道,%运算操作数不能为小数。而在Java中,允许操作数为小数。下方为代码示例:
public class Main {public static void main(String[] args) {System.out.println(11.5 % 2);System.out.println(11.5 % 2.5);}
}
此外,当左操作数为整数,/(除法运算)的右操作数不能为0,否则程序将抛出异常(即程序错误);当左操作数为小数,/(除法运算)的右操作数不能为0,否则程序结果为Infinity(无穷)。
public class Main {public static void main(String[] args) {System.out.println(11.5 / 0);System.out.println(10 / 0);}
}
ps:ArithmeticException为算术异常,我们将于后续文章介绍异常。
在%(取模运算)中,当左操作数为整数,%(取模运算)的右操作数不能为0,否则程序将抛出异常(即程序错误);当左操作数为小数,%(取模运算)的右操作数不能为0,否则程序结果为NaN(即无法表示的数学结果,Not a Number)。
public class Main {public static void main(String[] args) {System.out.println(11.5 % 0);System.out.println(10 % 0);}
}
增量运算符(+= -= *= /= %=)
下面先通过一段代码,以理解增量运算符的作用:
public class Main {public static void main(String[] args) {int a = 1;int b = 2;// += 增量运算符演示a += b;System.out.println(a);// -= 增量运算符演示a = 1;a -= b;System.out.println(a);// *= 增量运算符演示a = 1;a *= b;System.out.println(a);// /= 增量运算符演示a = 1;a /= b;System.out.println(a);// %= 增量运算符演示a = 1;a %= b;System.out.println(a);}
}
从上述代码及结果可知,a+=b
运算符的效果与a=a+b
似乎等效,-=
、*=
、/=
、%=
增量运算符同理。但实际两个语句存在一定差异,从下方代码可以得出。
public class Main {public static void main(String[] args) {int a = 1;long b = 665;a += b;System.out.println(a);}
}
当类型分别为int和long的两个操作数参与计算时,int类型将被提升为long类型,两者计算结果应为long类型。而long类型无法直接赋值给int类型的a变量,而需要强制类型转换。因而,int a=1; int b=2=665; a+=b;
与int a=1; int b=665; a=(int)(a+b);
等效,-=
、*=
、/=
、%=
增量运算符同理。
自增/自减运算符(++ --)
++
运算符用于给变量+1,--
运算符用于给变量-1。下面为演示代码。
public class Main {public static void main(String[] args) {int a = 1;System.out.println("原始a数值为 " + a);// ++运算符演示a++;System.out.println("a++后数值变为 " + a);++a;System.out.println("++a后数值变为 " + a);// --运算符演示a--;System.out.println("a--后数值变为 " + a);--a;System.out.println("--a后数值变为 " + a);}
}
那a++
和++a
存在什么差异呢?我们通过下方代码来解释:
public class Main{public static void main(String[] args) {int a = 2;int b = 3;int sum = a++ + b;System.out.println("a = " + a);System.out.println("b = " + b);System.out.println("sum = " + sum);System.out.println("=========");a = 2;b = 3;sum = ++a + b;System.out.println("a = " + a);System.out.println("b = " + b);System.out.println("sum = " + sum);}
}
不管是a++
还是++a
,都会给a自增1。区别在于sum = a++ + b;
在参与计算时,使用原始的a数值参与计算得到sum,再给a自增1;而sum = ++a + b;
在参与计算时,先给a自增1,再使用自增后的a参与计算得到sum。
总结
- 如果单独使用,前置++和后置++没有任何区别;
- 如果混合使用,前置++先+1,然后使用变量+1之后的值,后置++先使用变量原来的值,表达式结束时给变量+1;
- 只有变量才能使用自增/自减运算符,常量不能使用,因为常量不允许被修改。
关系运算符
关系运算符总共有6个,分别为==
、!=
、<
、>
、<=
、>=
。它们用于比较运算,运算结果为true或false。下方给出演示代码:
public class Main {public static void main(String[] args) {int a = 666;int b = 888;System.out.println(a == 666);System.out.println(a == b);System.out.println("=========");System.out.println(a != 666);System.out.println(a != b);System.out.println("=========");System.out.println(a < 0);System.out.println(a < b);System.out.println("=========");System.out.println(a > 0);System.out.println(a > b);System.out.println("=========");System.out.println(a <= 600);System.out.println(a <= b);System.out.println("=========");System.out.println(a >= 666);System.out.println(a >= b);}
}
与C/C++语言不同的是,Java不支持如下运算:
public class Main {public static void main(String[] args) {int a = 666;int b = 888;System.out.println(a < b < 800);}
}
上述代码中,比较运算符从左向右计算,a<b为true,而true为boolean变量,其无法与int类型的888进行比较,固程序错误。但上述a<b<800
在C/C++语言中,可以正常运行。
逻辑运算符
逻辑运算符包含&&
、||
、!
合计三种,其运算结果均为boolean类型,即true或false。
逻辑与 &&
语法格式为:表达式1 && 表达式2
,其中,表达式1和表达式2运算结果必须为boolean类型。
真假值判定口诀:两个表达式均为真,结果才为真;其中一个为假,结果则为假。详细真假值判定如下表所示。
表达式1 | 表达式2 | 结果 |
---|---|---|
真 | 真 | 真 |
真 | 假 | 假 |
假 | 真 | 假 |
假 | 假 | 假 |
下方给出演示代码:
public class Main {public static void main(String[] args) {int a = 1;int b = 2;// 表达式1为真 表达式2为真 结果为真System.out.println(a == 1 && b == 2);// 表达式1为假,表达式2为真,结果为假System.out.println(a != 1 && b == 2);// 表达式1为真,表达式2为假,结果为假System.out.println(a == 1 && b != 2);// 表达式1为假,表达式2为假,结果为假System.out.println(a != 1 && b != 2);}
}
逻辑或 ||
语法格式为:表达式1 || 表达式2
,其中,表达式1和表达式2运算结果必须为boolean类型。
真假值判定口诀:左右表达式其中一个为真,则结果为真。详细真假值判定如下表所示。
表达式1 | 表达式2 | 结果 |
---|---|---|
真 | 真 | 真 |
真 | 假 | 真 |
假 | 真 | 真 |
假 | 假 | 假 |
下方给出演示代码:
public class Main {public static void main(String[] args) {int a = 1;int b = 2;// 表达式1为真 表达式2为真 结果为真System.out.println(a == 1 || b == 2);// 表达式1为假,表达式2为真,结果为真System.out.println(a != 1 || b == 2);// 表达式1为真,表达式2为假,结果为真System.out.println(a == 1 || b != 2);// 表达式1为假,表达式2为假,结果为假System.out.println(a != 1 || b != 2);}
}
逻辑非 !
语法格式为:!表达式
,其中,表达式运算结果必须为boolean类型。
真假值判定口诀:真变假,假变真,详细真假值判定如下表所示。
表达式 | 结果 |
---|---|
真 | 假 |
假 | 真 |
下方给出演示代码:
public class Main {public static void main(String[] args) {int a = 1;// 表达式为真 结果为假System.out.println(!(a == 1));// 表达式为假 结果为真System.out.println(!(a != 1));}
}
短路求值
&&与||的短路求值规则
- 对于 && , 如果左侧表达式值为 false, 则表达式结果一定是 false, 无需计算右侧表达式。
- 对于 ||, 如果左侧表达式值为 true, 则表达式结果一定是 true, 无需计算右侧表达式。
我们知道10/0
会出现除零异常,但下方代码由于遵守上述短路求值规则,故不会抛出异常:
public class Main {public static void main(String[] args) {int a = 1;System.out.println((a != 1) && (10 / 0 == 0));System.out.println((a == 1) || (888 / 0 == 0));}
}
避免短路求值
若要避免上述的短路求值规则,可以将&&替换为&,||替换为|。&与|具备&&与||的同等逻辑效果,但与 && || 相比, 它们不支持短路求值。
&不支持短路求值,代码演示如下:
public class Main {public static void main(String[] args) {int a = 1;System.out.println((a != 1) & (10 / 0 == 0));}
}
|不支持短路求值,代码演示如下:
public class Main {public static void main(String[] args) {int a = 1;System.out.println((a == 1) | (888 / 0 == 0));}
}
位运算符
Java中数据存储的最小单位是字节,而数据操作的最小单位是比特。字节是最小的存储单位,每个字节由8个二进制的比特位组成,多个字节组合在一起可以表示各种不同的数据。
位运算表示按二进制位运算,即对比特位做运算。计算机中都是使用二进制来表示数据的(即数据都有1和0构成),按位运算就是按照每一位二进制位进行计算。
位运算符主要有4个,分别为:&
(按位与运算)、|
(按位或运算)、~
(按位取反)、^
(按位异或)。除了~
为一元运算符(单目运算符)外,其余都是二元运算符(双目运算符)。
按位与 &
运算规则:如果两个二进制位都是1,则结果为1,否则结果为0。
运算举例:在进行位运算时,要将待计算数值转换为二进制。例如:10的二进制位1010,22的二进制为10110,此时将两个进行按位与运算示意图如下:
ps:从上图中可以看出,仅有右往左数第二个比特位均为1,因而结果中仅有从右往左数第二个比特位为1,其余均为0。故得到结果为2。
代码验证:
public class Main {public static void main(String[] args) {int num1 = 10;int num2 = 22;System.out.println(num1 & num2);}
}
按位或 |
运算规则:如果两个比特位都是0,则结果为0,都则结果为1。
运算举例:在进行位运算时,要将待计算数值转换为二进制。例如:10的二进制位1010,22的二进制为10110,此时将两个进行按位或运算示意图如下:
ps:从上图中可以看出,除了左右两个比特位均为0外,其余位都存在至少一个为1的情况,因而结果中,左右两个比特位为0,其余均为1。故得到结果为30。
Attention:当&
、|
操作的数据为整数(byte、short、int、long)时,其表示位运算;当操作的数据为布尔类型(boolean)时,其表示逻辑运算,即非短路与和非短路或。
代码验证:
public class Main {public static void main(String[] args) {int num1 = 10;int num2 = 22;System.out.println(num1 | num2);}
}
按位取反 ~
运算规则:如果该位为0,则转为1;如果该位为1,则转为0。
运算举例:10的二进制表示为1010,将其各个二进制位1变0或者0变1。得到0101,其对应的十进制数为-11。示意图如下:
ps:10的二进制在取反后得到的是补码,由于这里的补码是个负数,需要将其转换为原码。转换规则为:补码的符号位不变,其余各位取反后加1,即可得到原码。
代码验证:
public class Main {public static void main(String[] args) {byte a = 10;System.out.println(~a);}
}
按位异或 ^
运算规则:如果两个二进制不同,则结果的二进制位为1;否则,结果的二进制位为0。
运算举例:10的二进制位1010,22的二进制为10110,此时将两个进行按位或运算示意图如下:
ps:除了上述框出来的二进制位不同,故其结果对应的二进制位为1,余下的二进制则为0,最终得到结果为28。
代码验证:
public class Main {public static void main(String[] args) {int a = 10;int b = 22;System.out.println(a ^ b);}
}
移位运算符
移位运算符顾名思义,就是对二进制进行移动。移位运算符共有3种,分别为<<
(左移运算符)、>>
(右移运算符)、>>>
(无符号右移)。
左移运算符 <<
运算规则:左侧比特位不要了,右侧比特位补0。
运算举例:byte类型的10,其二进制表示为0000 1010,将其向左移动右侧补0后得到0001 0100,其对应的十进制数为20。
代码验证:
public class Main {public static void main(String[] args) {byte a = 10;System.out.println(a<<1);}
}
与<<
配套的还有<<=
,其演示代码如下:
public class Main {public static void main(String[] args) {byte a = 10;a <<= 1;System.out.println(a);}
}
右移运算符 >>
运算规则:右侧比特位不要了,左侧比特位补符号位(即正数补0,负数补1)。
运算举例1:byte类型的10,其二进制表示为0000 1010,将其向右移动左侧补0(正数的符号位为0)后得到0000 0101,其对应的十进制数为5。
代码验证1:
public class Main {public static void main(String[] args) {byte a = 10;System.out.println(a >> 1);}
}
运算举例2:byte类型的-10,其原码二进制表示为1000 1010,再求其反码为11111 0101,再对其+1得到补码1111 0110。移位运算符都是对补码进行操作的。得到补码后,将其向右移动,左侧补1(其为负数,负数符号位为1),得到1111 1011。再将该补码转换为反码1000 0100,+1后得到原码1000 0101,即-5。
ps:>>
配套运算符为>>=
,这里代码顺带对其进行演示。
代码验证2:
public class Main {public static void main(String[] args) {byte a = -10;a >>= 1;System.out.println(a);}
}
无符号右移 >>>
运算规则:右侧比特位不要了,左侧比特位补0。
运算举例:byte类型的-10,其原码二进制表示为1000 1010,再求其反码为11111 0101,再对其+1得到补码1111 0110。移位运算符都是对补码进行操作的。得到补码后,将其无符号向右移动,左侧补0(其虽为负数,负数符号位为1,但这里是无符号右移,直接忽略符号位的存在),得到0111 1011。再将该补码转换为反码0000 0100,+1后得到原码0000 0101,即5。
代码验证:
public class Main {public static void main(String[] args) {byte a = 10;System.out.println(a >>> 1);}
}
ps:与>>>
配套的运算符为>>>=
,这里就不再赘述。需要注意的是,不存在无符号左移,即不存在<<<
和<<<=
。
Tips:为什么会有移位运算符的存在呢?
- 左移1位,相当于将原数字2;左移N位,相当于原数字2N2^N2N。
- 右移1位,相当于将原数字/2;右移N位,相当于原数字/2N2^N2N。
- 由于计算机中移位运算的效率高于乘除运算,当代码中需要乘除2的N次方时,可以用移位运算符替代。
- 对负数进行移位运算,或者被移位的位数过大,则其意义不大。
条件运算符
条件运算符只有一个,即表达式1 ? 表达式2 : 表达式3
。当表达式1的结果为true时,整个表达式的结果为表达式2的结果;当表达式1的结果为false时,整个表达式的结果为表达式3的结果。
该运算符为Java中唯一的三目运算符,该表达式可以简化条件判断语句。
下方代码运用条件运算符,选出最大值:
public class Main {public static void main(String[] args) {int a = 1;int b = 2;int max = a > b ? a : b;System.out.println("最大值为:" + max);}
}
注意事项1:表达式1 ? 表达式2 : 表达式3
中,表达式2和表达式3的结果必须为相同类型,
nice,bro!我写完了这篇文章了,你也看完这篇文章了!一起奖励自己一道力扣题吧~