第3章 运算符、表达式和语句 本章导图: 主要内容:  运算符与表达式。  选择控制。  循环控制。  跳转控制。 难点:  循环语句与跳转语句的掌握。 3.1运算符 运算符就是用来进行运算的符号。运算符通常必须与操作数一起使用组成Java 的表达式才有意义。Java 的运算符有多种,分为赋值运算符、算术运算符、关系运算符和逻辑运算符等。运算符按操作数的个数又可为单目运算符(如++、-)、双目运算符(如+、>)和三目运算符。 3.1.1赋值运算符与赋值表达式 赋值运算符为“=”,用于将运算符右边表达式的值赋给左边的变量。赋值运算符的使用格式如下。 变量=表达式; 下面是一些简单的赋值运算示例。 j=1; k=j; l=i+j*4; 3.1.2算术运算符与算术表达式 算术运算符用于完成算术运算,有双目运算符、单目运算符两种。 1. 双目算术运算符 双目算术运算符如表3.1所示。 表3.1双目运算符 运算符运算例子解释 +加a+b求a与b相加的和 -减a-b求a与b相减的差 *乘a*b求a与b相乘的积 /除a/b求a与b相除的商 %求余a%b求a除以b所得的余数 Java对加运算符进行了扩展,使它能够进行字符串的连接,如"abc"+"de",得到字符串"abcde"。与C、C++不同,对取模运算符%来说,其操作数可以为浮点数,如37.2%10=7.2。 2. 单目算术运算符 单目算术运算符如表3.2所示。 表3.2单目算术运算符 运算符运算例子解释 ++自增1a++或++aa=a+1 --自减1a--或--aa=a-1 -求相反数-aa=-a 需要注意的是,“++”和“--”在变量左右使用的区别。例如,i++与++i 是不一样的,i++发生在使用i之后,使i的值加1; ++i 发生在使用i 之前,使i 的值加1。i--与--i 类似。 例如: int x=2; int y=(++x)*3; 运行结果是x=3;y=9。 又例如: int x=2; int y=(x++)*3; 运行结果是x=3,y=6。 这是为什么呢?因为第一个例子中是x已经等于3后再算y,而后一个例子中则是先用x=2算出y后,再算x,因为++符号在后面,这就是++x 和x++的区别。下面的例子说明了算术运算符的使用。 例3.1 Example3_1.java public class Example3_1{ public static void main(String[] args) { // TODO code application logic here int a = 5 + 4; //a=9 int b = a * 2; //b=18 int c = b / 4; //c=4 int d = b - c; //d=14 int e = -d; //e=-14 int f = e % 4; //f=-2 double g = 18.4; double h = g % 4; //h=2.4 int i = 3; int j = i++; //i=4,j=3 int k = ++i; //i=5,k=5 System.out.print("a = " + a); System.out.println(" b = " + b); 图3.1例3.1的程序运行结果 System.out.print("c = " + c); System.out.println(" d = " + d); System.out.print("e = " + e); System.out.println(" f = " + f); System.out.print("g = " + g); System.out.println(" h = " + h); System.out.print("i = " + i); System.out.println(" j = " + j); System.out.println("k = " + k); } } 例3.1的程序运行结果如图3.1所示。 3.1.3关系运算符与关系表达式 关系运算符用来比较两个值,比较结果是布尔类型的值true 或false。关系运算符都是二元运算符,如表3.3所示。 表3.3关系运算符 运算符运算例子解释 ==等于a==ba等于b 为真,否则为假 !=不等于a!=ba不等于b 为真,否则为假 >大于a>ba大于b 为真,否则为假 <小于a=大于或等于a>=ba大于或等于b 为真,否则为假 <=小于或等于a<=ba小于或等于b 为真,否则为假 关系运算的结果是布尔值,只有“真”和“假”两种取值,例如: int x=5,y=7; boolean b=(x==y); 则b的值是false。 Java中,任何数据类型的数据(包括基本类型和组合类型)都可以通过==或!=来比较是否相等(这与C/C++不同)。关系运算的结果返回true 或false,而不是C/C++中的1 或0。关系运算符常与逻辑运算符一起使用,作为流控制语句的判断条件,如if(a>b&&b==c)。 3.1.4逻辑运算符与逻辑表达式 布尔逻辑运算符用来进行布尔逻辑运算,逻辑运算是针对布尔型数据进行的运算,运算的结果仍然是布尔型量。常用的布尔逻辑运算符如表3.4所示。 表3.4常用的逻辑运算符 运算符运算例子解释 &与x&yx,y都为真时结果才为真 |或x|yx,y都为假时结果才为假 !非!xx为真时结果为假,x为假时结果为真 ^异或x^yx,y都为真或都为假时结果为假 &&简洁与(条件与)x&&yx,y都为真时结果才为真 ||简洁或x||yx,y都为假时结果才为假 对于布尔逻辑运算,先求出运算符左边的表达式的值,对“或”运算,如果为true,则整个表达式的结果为true,不必对运算符右边的表达式再进行运算。同样,对“与”运算,如果左边表达式的值为false,则不必对右边的表达式求值,整个表达式的结果为false。 例3.2关系运算符和布尔逻辑运算符的使用。 Example3_2.java public class Example3_2{ public static void main(String args[]){ int a=25,b=3; boolean d=a= "+d1); else System.out.println(d1+" >= "+d2); } } 例3.3的程序运行结果如图3.3 所示。 3.2.2多分支语句(switch…case) switch语句又称为多分支语句,它根据表达式的值来选择执行多个操作中的一个,它的一般格式如下。 switch (表达式){ case 判断值1: 语句块1; break; case 判断值2: 语句块2;break; … case 判断值n:语句块n;break; [default:语句块n+1; ] } 语法说明: (1) switch 语句首先计算表达式,根据表达式的返回值与每个case 子句中的判断值进行比较,如果相等,则执行该case 子句后的语句块。 (2) 表达式的类型必须是byte、short、int 型和字符型,case 子句中的判断值必须为常量,类型与表达式的类型相同,所有case 子句中的判断值的值是不同的。 (3) default 子句是可选的。当表达式的值与任一case 子句中的判断值都不相等时,程序执行default 后面的语句块。如果表达式的值与任一case 子句中的判断值都不相等且没有default子句时,则程序不做任何操作,而是直接跳出switch 语句。 (4) break 语句用来在执行完一个case 分支后,跳出switch 语句,即终止switch 语句的执行。因为case 子句只是起到一个标号的作用,用来查找匹配的入口值,从此处开始执行,对后面的case 子句不再进行匹配,而是直接执行其后的语句序列,因此应该在每个case 分支后,用break 来终止后面的case 分支语句的执行。 在一些特殊情况下,多个不同的case 值要执行一组相同的操作,这时可以不用break。 (5) switch 语句的功能可以用if…else 来实现,但在某些情况下,使用switch 语句更简练,可读性更强,且程序的执行效率更高。 例3.4根据考试成绩的等级打印出百分制分数段。从本例中可以看到break 语句的作用。 Example3_4.java public class Example3_4{ public static void main( String args[] ){ System.out.println("** 正确用法**"); char grade='C'; //正确用法 switch( grade ){ case 'A': System.out.println(grade+" is 85~100"); break; case 'B': System.out.println(grade+" is 70~84"); break; case 'C': System.out.println(grade+" is 60~69"); break; case 'D': System.out.println(grade+" is <60"); break; default: System.out.println("输入错误"); } System.out.println("** 不含break 的case 语句**"); grade='A'; //一个不含break 的case 语句 switch( grade ){ case 'A': System.out.println(grade+" is 85~100"); case 'B': System.out.println(grade+" is 70~84"); case 'C': System.out.println(grade+" is 60~69"); case 'D': System.out.println(grade+" is <60"); default: System.out.println("输入错误"); } System.out.println("** 部分含break 的case 语句**"); grade='B'; //部分含break 的case 语句 图3.4例3.4的程序运行结果 switch( grade ){ case 'A': case 'B': case 'C': System.out.println(grade+" is >=60"); break; case 'D': System.out.println(grade+" is <60"); break; default: System.out.println("输入错误"); } } } 例3.4的程序运行结果如图3.4所示。 3.3循 环 控 制 循环语句的作用是反复执行一段代码,直到满足终止循环的条件为止。 一个循环语句一般应包括以下四部分内容。 循环初始化部分,用来设置循环的一些初始条件,使计数器清零等。 循环体部分,这是反复循环的一段代码,可以是单一的一条语句,也可以是复合语句。 迭代部分,这是在当前循环结束后,下一次循环开始前时执行的语句,常常用来使循环计数器加1 或减1。 终止部分,通常是一个条件表达式,每一次循环要对该表达式求值,以验证是否满足循环终止条件。 Java提供的循环语句有for 语句、while 语句、do…while 语句等。 3.3.1for语句 for语句是最常使用的一种循环语句,它的一般格式为: for (初始化表达式; 终止表达式; 迭代表达式){ 循环体} 语法说明: (1) for 语句执行时,首先执行初始化操作,然后判断终止条件是否满足,如果满足,则执行循环体中的语句,最后执行迭代部分。完成一次循环后,重新判断终止条件。 (2) 可以在for 语句的初始化部分声明一个变量,它的作用域为整个for 语句。 (3) for 语句通常用来执行循环次数确定的情况(如对数组元素进行操作),也可以根据循环结束条件执行循环次数不确定的情况。 (4) 在初始化部分和迭代部分可以使用逗号语句,来进行多个操作。逗号语句是用逗号分隔的语句序列。例如: for(i=0,j=10;i 0) { sum += n; n--; } System.out.println("sum is " + sum); System.out.println("** do_while 语句**"); n = 0; sum = 0; do { sum += n; n++; 图3.6例3.6的程序运行结果 } while (n <= 10); System.out.println("sum is " + sum); System.out.println("** for 语句**"); sum = 0; for (int i = 1; i <= 10; i++) { sum += i; } System.out.println("sum is " + sum); } } 例3.6的程序运行结果如图3.6 所示。 3.4跳 转 控 制 在程序执行时,跳转控制语句可使程序的执行流程转向。Java 的跳转控制语句有break、continue 和return 三种。Java 中没有goto 语句来实现任意的跳转,因为goto 语句会破坏程序的可读性,而且影响编译的优化。 3.4.1break语句 在switch 语中,break 用来终止switch 语句的执行,程序流程转向switch 语句后的第一条语句。同样,在循环语句for、while、do…while 中,break 立即终止正在执行的循环,程序流程转向循环语句后的第一条语句。 break语句分为不带标号的break 语句和带标号的break 语句。 不带标号的break 的语法格式为: break; 带标号的break 的语法格式为: 标号: 语句块 break标号; 语法说明: (1) 不带标号的break 语句终止当前语句的执行,程序流程转向到从当前语句的下一条语句开始执行。 (2) 带标号的break 语句从当前正在执行的程序中跳出,程序流程转向到标号后语句开始执行。 例如在以下代码中,执行了break b 后,程序流程转向到用标号b 标识的、用大括号{}括起来的一段代码。 {… b: {… //标号b {… break b; //转移到标号b 后的语句块执行 … } … } … } 可以看出,Java 用break语句可实现goto 语句所特有的一些优点。如果break语句后指定的标号不是一个代码块的标号,而是一个语句,则这时break语句完全实现goto语句的功能,不过应该避免这种方式的使用。 3.4.2continue语句 continue语句只能用在循环语句中,它中断本次循环,立即开始下次循环。 continue语句也分为不带标号的continue 语句和带标号的continue 语句。 不带标号的格式为: continue; 带标号的格式为: continue标号; 语法说明: (1) 不带标号的continue 语句使控制无条件地转移到循环语句的条件判定部分,即首先结束本次循环,跳过循环体中下面尚未执行的语句,接着进行终止条件的判断,以决定是否继续循环。对于for 语句,在进行终止条件的判断前,还要先执行迭代语句。 (2) 带标号的continue 语句通常用在多重循环中,标号应放在外循环的开始处。例如,在以下代码中,当满足j>i 的条件时,程序执行continue outer 后,立即从内循环跳转到标号outer 标志的外循环。 outer: for( int i=0; i<10; i++){ //外循环 for( int j=0; j<20; j++){ //内循环 if( j>i ){ … continue outer; //跳出内循环,开始下一次外循环 } … } … } 例3.7求100~200的所有素数。本例通过一个嵌套的for 语句来实现。 Example3_7.java public class Example3_7{ public static void main(String args[]){ System.out.println(" ** 界于100 — — 200 的素数**"); int n=0; outer: for(int i=101;i<200;i+=2){ int k=15; for(int j=2;j<=k;j++){ if(i%j==0) continue outer; } System.out.print(" "+i); n++; if(n<10) continue; System.out.println(); n=0; } System.out.println(); } } 例3.7的程序运行结果如图3.7 所示。 图3.7例3.7的程序运行结果 3.4.3return语句 return语句从当前方法中返回到调用该方法的语句处,并继续执行后面的语句(有关方法的内容,将在第6章介绍)。返回语句有以下两种格式。 第一种格式: return 表达式; 第二种格式: return; 语法说明: (1) 第一种return 语句返回一个值给调用该方法的语句,返回值的数据类型必须与在方法声明中的返回值类型一致,如果不一致可以使用强制类型转换来使类型一致。 (2) 第二种return 语句不返回任何值。 (3) return 语句通常用在一个方法体的最后,退出该方法并返回一个值。Java 中单独的return语句用在一个方法体的中间时,会产生编译错误,因为这时会有一些语句执行不到。但可以通过把return 语句嵌入某些语句中(如if…else)使程序在未执行完方法中的所有语句时退出。 例如在下例中,方法method 根据num 是否大于0,决定是否返回整数num。 int method (int num){ if (num>0) return num; //如果num>0 ,返回整数num … } 3.5其 他 语 句 Java除了常规的流程控制语句外,还有特殊的语句,如异常处理语句。另外,Java 同样也有注释语句,用来专门在程序中给出注释。 异常处理语句包括try、catch、finally 以及throw、throws 语句。异常处理语句是Java所特有的,将在后面章节中做专门的介绍。 Java中可以采用下面三种注释方式。 ∥——用于单行注释。注释从∥开始,终止于行尾。 /*… */——用于多行注释。注释从/*开始,到*/结束,且这种注释不能互相嵌套。 /**… */——是Java 所特有的java doc 注释。它以/**开始,到*/结束。这种注释主要是为支持JDK 工具javadoc 而采用的。javadoc 能识别注释中用标记@标识的一些特殊变量,并把java doc注释加入它所生成的HTML 文件。对javadoc 的详细讲述可参见JDK 的相关工具参考书。 应用实例 视频讲解 3.6应用实例: 图形界面的简单计算器 利用NetBeans可视化的图形界面开发工具,结合本章所学内容可实现一个图形界面的简单计算器。 打开NetBeans开发工具,选择“文件”→“新建项目”命令,项目名称设置为“JFrameCal”,主类设置为“Main”,如图3.8所示。 项目建立完成后,鼠标右击主类Main.java所在的包jframecal,在弹出的快捷菜单中选择“新建”→“JFrame窗体”命令,如图3.9所示。 在新建窗体的对话框中将类命名为CalJFrame,如图3.10所示。 选中新建的CalJFrame.java,可以通过NetBeans的可视化功能对计算器的界面进行编辑,在开发工具右上侧的组件面板中选中“文本字段”,可用鼠标拖放到窗体上,并可适当调整其大小和位置,如图3.11所示。文本字段可用于让用户输入文本信息。 图3.8新建Java应用程序 图3.9选择“新建”→“JFrame窗体”命令 图3.10在“New JFrame窗体”对话框设置名称和位置 图3.11窗体的可视化编辑界面 继续在窗体中拖入另一个文本字段。这两个文本字段用于用户录入两个操作数。选中任一文本字段,在开发工具的右下侧属性窗体中,可将文本字段的Text属性设置为空,如图3.12所示。 图3.12修改文本字段的Text属性 在窗体中继续拖放入一个组合框,单击组合框的model属性按钮,如图3.13所示。 图3.13单击组合框model属性按钮 在model属性的设置对话框中,将组合框项设置为“+、-、*、/”四项,如图3.14所示。通过该组合框可让用户选中适当的运算符进行运算。 图3.14组合框model属性的设置 最后在窗体上拖入一个标签和一个按钮组件。将标签的Text属性设置为“结果”,用于显示最终的运行结果。将按钮的Text属性设置为“运算”,单击该按钮进行运算,并将运算结果显示在结果标签上。最终的界面如图3.15所示。 图3.15修改按钮的Text属性 至此,整个计算器的界面由两个文本字段、一个组合框、一个标签和一个按钮构成。在开发工具左下角的“导航器”窗口中可以看到,这些组件所对应的对象名依次为jTextField1、jTextField2、jComboBox1、jLabel1和jButton1,如图3.16所示。 图3.16开发工具左下角的“导航器”窗体 单击CalFrame.java的“源”视图可切换到该类的源代码编辑界面,单击“设计”视图可重新切换到可视化的编辑界面,如图3.17所示。 图3.17“源”视图与“设计”视图 在源代码编辑界面,CalJFrame类中定义三个私有成员变量,如图3.18所示。 图3.18在CalJFrame类中定义三个私有成员变量 同第2章控制台简单计算器类似,double类型的num1和num2这两个变量用来保存运算用的操作数1和操作数2; 而char类型的sign变量用来保存所使用的运算符。 重新切换至“设计”视图,鼠标右击“计算”按钮,在弹出的右键菜单中依次选择“事件”→Action→actionPerformed命令,为“计算”按钮增加相应的单击事件的处理程序(具体原理会在第9章Java Swing图形用户界面中进行详细阐述)。在自动生成的jButton1ActionPerformed(java.awt.event.ActionEvent evt)方法中对计算过程进行具体实现,其详细代码如下。 private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) { //通过文本字段获得第一个操作数 String snum1=this.jTextField1.getText().trim(); //通过文本字段获得第二个操作数 String snum2=this.jTextField2.getText().trim(); //将第一个操作数由String类型转换为double类型 num1=Double.parseDouble(snum1); //将第二个操作数由String类型转换为double类型 num2=Double.parseDouble(snum2); //通过组合框获取运算符 sign=this.jComboBox1.getSelectedItem().toString().charAt(0); //设置运算结果,初始值为0 double result=0; //根据运算符进行相应运算 switch(sign) { case '+': result = num1 + num2; break; case '-': result = num1 - num2; break; case '*': result = num1 * num2; break; case '/': result = num1 / num2; break; } //将运算结果转换为String类型设置到标签的Text属性 this.jLabel1.setText(String.valueOf(result)); } 图形界面的简单计算器的程序运行结果如图3.19 所示。 图3.19图形界面的简单计算器的程序运行结果 小结 本章重点介绍了Java表达式和各种运算符的使用方法、Java 的控制语句(用于判断的if 和if…else,选择结构switch,循环结构do…while、while、for),并介绍了跳转语句的使用。 在编写程序的时候,构造良好的控制结构,可提高整个程序的质量和可读性。 习题 1. 用for循环结构求出1~100 中所有偶数的和。 2. 用while循环语句和计数变量x 打印1~50中的奇数。要求每行只打印6 个。 3. 编制程序计算1+1/2+1/4+1/8+…+1/100 的和。 4. 编制程序输出一个杨辉三角形。 5. 求阶乘n!,分别采用int 和long 数据类型,看n在什么取值范围内,结果不会溢出。 6. 输出100000以内的所有完全数,如果一个数恰好等于它的所有真因子(即除了自身以外的约数)的和,则称该数为“完全数”。例如,第一个完全数是6,它有约数1、2、3、6,除去它本身6外,其余3个数相加1+2+3=6。