第二章《Java程序世界初探》第9节:逻辑运算符

本文详细介绍了Java语言中的逻辑运算符,包括单目与双目运算符的区别,以及&&、||、&、|和!的具体用法。通过实例说明了短路效果的概念,并展示了如何运用逻辑运算符构建复杂条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java语言的逻辑运算符有:&&、||、&、|和!。按照其运算所需操作数的多少,逻辑运算符可以分为单目运算符和双目运算符。单目逻辑运算符有只有一个,其写法是“!” ,它表示“非”,用于对某个条件进行“取反”操作。而双目逻辑运算符有4个,分别是&&、||、&、|,它们都用于描述两个条件之间的关系。本小节首先讲解使用频率较高的双目逻辑运算符。

2.9.1 双目逻辑运算符

前文在讲解if语句的所有示例中,if关键字后面的小括号中都仅列出了一个条件。但在实际开发过程中,一段代码能否执行可能会受到多个条件的制约。这就要求程序员把所有制约代码运行的条件全部列出,并且描述清楚这些条件之间的关系,这样虚拟机才能判断出是否可以运行条件语句中的代码。

其实,条件与条件之间的关系无非只有“并且”和“或者”两种。所谓“并且”就是指两个条件都要成立,Java语言用&&表示两个条件之间这种“并且”的关系,例如,程序员希望在变量a大于等于0并且小于等于100的情况下执行一条语句,不能按照数学上的格式写为0<=a<=100,而是应该写成:

if(a>=0 && a<=100){
    System.out.println(“条件成立!”);//①
}

在以上代码中,语句①是否能运行取决于两个条件,分别是“a>=0”和“a<=100”。只有这两个条件都成立的情况下,语句①才能执行,反之,两个条件中任意一个不成立,语句①都不能执行。此处可以看出:同关系运算符一样,逻辑运算符运算的最终结果也是一个boolean型的数据,但逻辑运算符中除了!以外,其他逻辑运算符都比关系运算符的优先级低。也就是说,在计算表达式“a>=0 && a<=100”时,虚拟机首先会判断“a>=0”是否为true,之后判断“a<=100”是否为true,在结束了两次关系运算符的运算之后,才通过逻辑运算符&&来判断整个逻辑表达式是否为真。

在实际开发中,程序员可以使用逻辑运算符来判断多个“子条件”所组成的“总条件”是否成立。下面来看一个逻辑运算符在实际开发中的应用案例:小白应聘。小白想去应聘某公司会计职位,公司要求应聘者必须年满20周岁,并且至少有1年工作经验。编写程序:由应聘者输入年龄和工作年数,判断该应聘者是否达到应聘要求。

通过阅读题目不难发现,公司要求的“年满20周岁”和 “至少有1年工作经验”这两个条件是“并且”的关系,即二者都要满足,因此要用&&运算符来表示两个条件之间这种逻辑关系,程序完整代码如下:

【例02_09 小白应聘】

Exam02_09.java

import java.util.Scanner;
public class Exam02_09 {
	public static void main(String[] args) {
		int age;// 年龄
		int workYear;// 工作经验
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入年龄:");
		age = sc.nextInt();
		System.out.println("请输入工作经验(年):");
		workYear = sc.nextInt();

		if (age >= 20 && workYear >= 1) {// 使用&&判断两个条件是否都成立
			System.out.println("达到要求!可以应聘!");
		} else {
			System.out.println("未达到应聘要求!");
		}
	}
}

以上程序的if条件中用&&运算符表示出了“年满20周岁”和“至少有1年工作经验”这两个条件的逻辑关系是“二者必须同时满足”。如果小白能够同时达到两个必备条件,程序运行效果如图2-15所示。

图2-15 同时满足2个应聘条件的运行结果

如果小白仅能达到“有至少1年工作经验”这1个条件,则运行结果为图2-16所示。

图2-16 仅满足1个应聘条件的运行结果

在这个例子中,公司所列出的两个招聘条件是“并且”的关系。如果公司把两个招聘条件修改为“或者”的关系,就可以用||运算符来表示这种逻辑关系。所谓“或者”,就是指这两个条件只要满足其中一个,就达到了语句的执行条件。以下逻辑表达式就表示了两个条件之间是 “或者”的关系:

age>=20 || workYear>=1

以上所有例子中都仅有两个条件,它们要么是“并且”的关系,要么是“或者”的关系。如果逻辑表达式中有多个条件,并且同时出现了&&和||两种运算符,程序员就必须弄清楚这两种运算符优先级的高低,否则很有可能无法写出正确的逻辑表达式。在Java语言中,&&的运算优先级高于||,也就是说,逻辑表达式中如果同时出现了&&和||,并且逻辑表达式中没有出现小括号,则虚拟机会优先运算所有的&&,之后才去运算||。下面来看几个&&和||同时出现的情况。

假设公司在设置招聘条件的时候,还考会参考应聘着是否拥有注册会计师证书。如果应聘者没有注册会计师证书,则必须同时满足“年满20周岁”和“至少有1年工作经验”这两个条件。但应聘者如果拥有注册会计师证书,则可以不受年龄和工作经验的限制,直接获得应聘资格。这样的招聘规则可以用如下逻辑表达式完成判断:

age>=20 && workYear>=1 || cpa==true

这个表达式中出现了一个新的变量cpa,它是一个布尔型变量,表示是否拥有注册会计师证书。因为&&优先级较高,所以虚拟机在计算这个表达式的时候,会首先运算&&符号。也就是说,虚拟机会先看应聘者是否同时满足“年满20周岁”和“至少有1年工作经验”这两个条件,之后才去看应聘者是否拥有拥有注册会计师证书。读者必须清楚这两个考察步骤的先后顺序。

有时候,需要提升||运算符的优先级,就如同在算术表达式中需要把+的优先级提升到高于*优先级一样,可以通过添加小括号的方式实现,例如:

age>=20 && (workYear>=1 || cpa==true)

在这个逻辑表达式中,用小括号提升了||运算符的优先级。因此表达式的意义就发生了变化,在这个表达式中,“年满20周岁”成为了一个必须满足的硬性条件,而在此基础上,应聘者要么有至少1年工作经验,要么有注册会计师证书才能获得应聘资格。而虚拟机在判断的过程中,因为要优先判断小括号内的条件,所以判断的顺序是:先看应聘者是否有1年以上工作经验或者是有注册会计师证书,两个条件至少要达到一个,然后再看应聘者是否年满20周岁。因为小括号的出现,&&会被放在最后被运算,这就使得&&左边的“age>=20”成为了整个逻辑表达式能否为true的一个硬性条件。一旦“age>=20”不成立,即使小括号中的表达式的计算结果为true,整个逻辑表达式的值仍然是false。

通过以上几个例子可以看出:使用&&和||配合可以表示出很复杂的条件,但同时也要注意到,一旦逻辑表达式的写法发生了改变,就可能导致整个逻辑表达式的含义发生根本性的变化。比如在上面的例子中,仅仅在逻辑表达式中添加了一对小括号, “拥有注册会计师证书”这个条件就由原来的 “不受年龄和工作经验限制”直接变成了仅仅与工作经验地位平等的一个 “参考条件”。因此建议各位读者在书写一个较为复杂的逻辑表达式之前,一定要仔细考虑清楚各项条件之间的关系,做到心中有数后再动手写代码。

各位读者可以把以上列举的几种情况代入到【例02_09】的代码中,体验一下不同的应聘条件应该怎样用哪一种逻辑表达式表示。

在本小节的开头曾经介绍过:&和|也是双目逻辑运算符。那么,&&与&,以及||与|之间有什么相同点和不同点呢?相同点是:&&和&都是表示两个条件为“并且”关系的运算符,而||和|都是表示两个条件为“或者”关系的运算符。而不同点是:&&和||在运算过程中都有“短路”效果,而&和|没有“短路”效果

所谓“短路”效果就是指&&左边的条件如果不成立,虚拟机将不会去计算&&右边的条件是否成立,因为&&左边的条件一旦不成立,&&右边的条件无论是否成立,整个逻辑表达式的值都是false。对右边条件的计算不会改变整个逻辑表达式的值。例如,在【例02_09】中,公司设定的招聘条件为“年满20周岁”并且“有至少1年工作经验”,判断应聘者是否有资格应聘该职位的表达式为:

age>=20 && workYear>=1

在该表达式中使用了&&来表示两个条件之间是“并且”关系。因为&&具有短路效果,应聘者的年龄一旦不满20岁,无论他是否有至少1年的工作经验,都不具备应聘资格,因此在这种情况下,虚拟机不会计算“workYear>=1”的值是否为true。而&虽然也表示“并且”,但它没有短路效果,所以即使&左边的条件不成立,虚拟机仍然会计算&右边的条件是否成立。

同理,||也具有短路效果,只是短路的条件变成了:||左边的条件为true。一旦虚拟机计算出||左边的条件为true,都不再计算右边的条件是否成立。而|虽然也表示“或者”,但它也没有短路效果。读者可以通过下面的例子体验短路效果:

【例02_10 逻辑运算符的短路效果】

Exam02_10.java

public class Exam02_10 {
	public static void main(String[] args) {
		int a = 1;
		int b1 = 2, b2 = 2, b3 = 2, b4 = 2;
		boolean r1 = (a < 0) && (++b1 == 0);// ①短路
		boolean r2 = (a < 0) & (++b2 == 0);// ②不短路
		boolean r3 = (a > 0) || (++b3 == 0);// ③短路
		boolean r4 = (a > 0) | (++b4 == 0);// ④不短路

		System.out.println("b1==" + b1);
		System.out.println("b2==" + b2);
		System.out.println("b3==" + b3);
		System.out.println("b4==" + b4);
	}
}

程序执行的效果为:

b1==2
b2==3
b3==2
b4==3

在【例02_10】中,虚拟机在执行语句①时,看到&&左边的条件“a<0”不成立,根据短路原则,不再计算右边的条件,“++b1”这一步操作不会执行,因此语句执行后,b1仍然保持原始值2。而语句②中,使用了不短路的&,虚拟机虽然看到“a<0”不成立,但仍然计算了右边的条件,“++b2”这一步操作得以执行,因此语句执行后b2的值变成了3。各位读者可以根据程序运行结果自行分析语句③和④的执行原理。

在实际开发过程中,建议大家尽量使用具有短路效果的&&和||,这不仅仅是因为它们的执行效率更高,更重要原因是:&和|这两个运算符与位运算符中的“按位与”和“按位或”运算符的写法完全相同,在某些场合下容易引起误解。

2.9.2 单目逻辑运算符

在Java语言中,单目逻辑运算符只有一个,那就是“!”。!运算符可以与某个逻辑表达式组合在一起,形成一个新的逻辑表达式,它的作用是对原有逻辑表达式进行“取反”操作。这有点像数学中的负号(-),一个正数在前面加上一个负号,所形成的新值就是一个负数。同样,一个逻辑表达式原来的值为true,在前面加上!运算符之后,所形成的新逻辑表达式的值就变成了false,而如果逻辑表达式原来的值为false,在前面加上!运算符之后,所形成的新逻辑表达式值就变成了true。

在实际开发中,!运算符经常用来表示一种 “否定形式”的条件,例如,如果希望变量a不在[0-100]区间内时执行语句,就可以用如下方式编写代码:

if(!(a>=0 && a<=100)){
    System.out.println(“执行语句”);
}

在这段代码中,先用表达式 “a>=0 && a<=100”设定了a的范围在[0-100]之间,然后前面加上!运算符,就表示出了a不在这个区间内才符合语句的执行条件。当然,程序员也可以直接把表达式写成:

a<0 || a>100

这同样可以表示出a不在[0-100]这个区间内才满足运行条件。

!运算符的含义及用法不难理解和掌握。但初学Java的读者还是要注意两个很重要的细节:

1. !运算符并不能改变原有boolean型变量的值。例如:

boolean a=true;
boolean b = !a;//对a取反后赋值给b
System.out.println(a);

在以上代码中,变量a的初始值为true,使用!运算符对其取反并赋值给变量b,因此b的值为false。很多初学者会理解为:在a的前面加上了!,会把a的值修改成false,然后赋值给b。这是一种典型的错误理解,虽然在a的前面加上了!,但虚拟机并不会改变a的值,而是把!运算符与变量a组成了一个新的表达式,这个新表达式的值是false,然后把这个新表达式的值赋给了变量b,而a的值并没有发生变化,仍然是true。因此!运算符并没有改变变量值的功能,它仅仅是与变量组成了新表达式。

2.!运算符的优先级非常高

在Java语言中,优先级最高的运算符是小括号,而!运算符的优先级仅次于小括号。此处特意强调!运算符优先级高,是因为很多初学者不清楚这个特性,导致对出现了!运算符的表达式理解错误,例如:

boolean a=true;
boolean b = !a==true;

在这段代码中,给变量b赋值的是“!a==true”。很多初学Java的读者可能会认为,!运算符是与表达式“a==true”完成了组合,其实并非如此。!运算符的优先级要比==更高,所以虚拟机会优先运算!,也就是说,虚拟机会先把!与变量a组合在一起,然后才用==运算符比较!a与true的值是否相等,最终把比较的结果赋值给b。因此,在“!a==true”这个表达式中,与!组合的并不是“a==true”,而仅仅是变量a。如果希望!与“a==true”完成组合,需要在“a==true”的两端加上小括号。虽然无论是否添加小括号,变量b的值最终都是false,但意义完全不同。由于!运算符的优先级很高,所以只要!运算符一出现在某个表达式的前面,就会立刻与表达式最前面的部分组合在一起。所以,如果想让!运算符与整个表达式,而不是仅仅与表达式的最前面那一部分进行组合,就必须把整个表达式用小括号括起来。

除阅读文章外,各位小伙伴还可以点击这里观看我在本站的视频课程学习Java!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

穆哥讲Java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值