Java语句及其控制结构 任何Java程序都是由类和对象组成的,对象和类是由变量与方法组成的,变量由声 明变量语句与赋值语句构成,方法由一系列执行不同功能的Java语句构成。Java语句有 不同的类型,不同类型的语句其组成成分不同、含义不同、作用不同,有的语句在程序中的 位置顺序也有一定的规则,这些也是Java语言的基本语法内容。学习Java程序设计,就 是要了解不同Java语句的构成方式、含义与作用,了解如何组织Java语句构建Java类与 对象的框架,定义变量确定类与对象的特性,定义方法实现与控制类的功能。 本章的内容主要解决以下问题。 .Java程序有哪些主要构成成分? .Java类有哪些主要构成成分? .Java有哪些类型的语句? .Java的选择语句是如何构成的? 其作用是什么? .Java的循环语句是如何构成的? 其作用是什么? .Java的跳转语句是如何构成的? 其作用是什么? 3.1 Java语句的类型 本节主要介绍Java程序的构成成分、类的构成成分、Java语句的种类以及说明性语 句、表达式语句和复合语句的特点。 3.1.1 Java程序构成 例3.1 一个程序范例,用来说明Java程序的构成成分。 import java.awt.*; import javax.swing.*; ù . úú Java 包引入语句 public class exp3_1 extends JFrame ———类声明语句 ·45· { Label label1=new Label("类的结构"); ———成员变量 public exp3_1 () { setSize(400, 200); setVisible(true); add("North", label1); } ù . úúúúúú 构造方法 public void paint(Graphics g) { g.fillRect(100, 80, 80, 100); } ù . úúú paint 方法 public static void main(String[] args) { new exp3_1(); } ù . úúú main 方法 } ù . úúúúúúúúúúúúúúúúúú 类体 说明: (1)程序的主要构成。从例3.1可以看到,Java程序一般包括两部分:Java包引入 (如果有的话)语句、类定义语句。类定义语句由类声明语句和类体组成。 (2)类声明语句。类声明语句用class来声明类的名称,其他关键字为修饰符,来说 明类的访问权限,以及类的属性。详细介绍看第4章。 (3)类体。类体由成员变量和成员方法等组成。成员变量表示类的属性,是数据域 的形式表达;方法是数据的操作的定义。在exp3_1类中,label1成员变量,其他是成员 方法。成 员变量在类中定义时,需要声明成员变量的名称、类型或初值。 成员方法是命令语句的集合,用来实现类的功能和行为,是程序设计的关键。 (4)主类与普通类。类可以分为主类与普通类。 Java程序中,必须含有一个可被外界(通常是Java解释器)直接调用的类,这个类称 为这个Java程序的主类,即可以被运行的类。主类常用public关键字来修饰。一个Java 程序中可以定义多个类,但只能有一个主类,主类中一定包含main方法,其用来控制程 序进行数据初始化工作,实现不同的功能或调用其他对象,输出程序运行后的结果。整个 应用程序是从main方法开始执行的。 不是主类的类都是普通类,可以用来定义属性、方法,设计对象的功能。 3.1.2 Java语句的种类 Java语句是Java标识符的集合,由关键字、常量、变量和表达式构成。简单的Java 语句以分号(;)作为结束标志,单独的一个分号被看作一个空语句,空语句不做任何事情。 复合结构的Java语句以花括号(})作为结束标志,凡是可以出现语句的地方,都可以出现 复合语句。 Java语句一般分为说明性语句和操作性语句两种类型。 ·46· 1.说明性语句 Java的说明性语句包含包和类引入语句、声明类语句、声明变量语句、声明对象语句 等。例如: import java.sql.Connection; //包引入语句 public class ReadViolation; //声明类语句 int i; //声明变量语句 2.操作性语句 Java的操作性语句包含表达式语句、复合语句、选择语句和循环语句、跳转语句等。 Java规定所有的操作性语句必须放在成员方法中。 下面介绍表达式语句与复合语句的构成,其他操作性语句将分别在后面介绍。 1)表达式语句 在表达式后边加上分号(;)就是一个表达式语句。表达式语句是最简单的语句,它们 被顺序执行,完成相应的操作任务。表达式语句主要有赋值语句和方法调用语句。 例如: int x, i=1, j=2; //声明变量语句 x=j-i; //赋值语句 System.out.println("x:"+k); //方法调用语句 注意:声明变量时可以直接赋初值,但不属于赋值语句,为声明变量语句。 2)复合语句 复合语句也称为块(block)语句,是包含在一对花括号({})中的任意语句序列,由一 组0和多条语句组成。与其他语句用分号作结束符不同,复合语句右括号(})后面不需要 分号。尽管复合语句含有任意多个语句,但从语法上讲,一条复合语句被看作一条简单 语句。例 3.2 复合语句示例,程序运行结果为“Conditionistrue.”。源代码如下所示: public class exp3_2 { public static void main(String[] args) { boolean condition=true; if (condition) { //执行第一个块语句 System.out.println("Condition is true."); } //结束block1 else { //执行第二个块语句 System.out.println("Condition is false."); } //结束block2 } } 说明:在程序中通过两条复合语句实现了对于condition条件的判断,如果condition 为真,则执行第一个块语句block1,否则执行第二个块语句block2。在实际应用中,复合 ·47· 语句更广泛地应用在结构式语句中。 3.2 选择语句 表达式语句与复合语句都是按顺序从上到下逐行执行每条命令。能否改变程序中语 句执行的顺序呢? 利用选择语句结构就可以根据条件控制程序流程,改变语句执行的 顺序。本 节主要介绍Java的4种选择语句:单分支选择语句(if语句)、二分支选择语句 (if…else语句)、多分支选择语句(if…elseif…else语句)和先执行后判定循环(do…while) 的使用方法。 3.2.1 单分支选择语句(if语句) 单分支选择语句是一种简单的if条件语句,其语法格式如下: if (条件){ s1(语句); } 图3.1 if条件语句执行结果 这是最简单的单分支结构。当构成条件的逻辑或关系 表达式的值为true时,执行s1语句,否则忽略s1语句。s1 语句可以是复合语句,如果只有一条语句,花括号可以省略 不写。条件是必要的参数,可以由多个表达式组成,但是, 最后结果一定是boolean类型,其返回的结果值一定是true 或者false。if条件语句执行结果如图3.1所示。 3.2.2 二分支选择语句(if…else语句) if语句通常与else语句配套使用,形成二分支结构。它的语法格式为: if (条件){ s1 语句; //如果条件表达式的值为true }else{ s2 语句; //如果条件表达式的值为false } 图3.2 if…else语句执行结果 当构成条件的逻辑或关系表达式的值为true时, 执行s1语句,忽略else和s2语句;否则,条件表达式 的值为false,程序忽略s1语句,执行else后面的s2语 句。s1和s2都可以是复合语句。if…else语句执行结 果如图3.2所示。 例3.3 判断两个数的大小并输出指定语句,程序 运行结果为“这是if语句”,源程序代码如下所示: ·48· public class exp3_3 { public static void main(String args[]){ int x=10; if(x<20){ System.out.print("这是if 语句");} else{ System.out.print("这是else 语句");} } } 说明:程序通过if…else语句实现了对传入参数的比较判断功能。参数x的值为 10,小于20,条件判断x<20的值为true,因此执行输出“这是if语句”,忽略else语句,最 终输出“这是if语句”。 3.2.3 多分支选择语句(if…elseif…else语句) 对于超过二分支选择的情况,可以使用多分支选择语句(if…elseif…else语句)。它 的语法格式为: if (条件1) s1 语句; //如果布尔条件1 的值为true 执行s1 语句 else if (条件2) s2 语句; //如果布尔条件2 的值为true 执行s2 语句 else if (条件3) s3 语句; //如果布尔条件3 的值为true 执行s3 语句 else s4 语句; //如果以上布尔条件都不为true 执行s4 语句 在这里依次计算条件的值,如果某个条件的值为true,就执行它后面的语句,其余语 句被忽略;所有条件的值都为false,就执行最后一个else后的s4语句。s1、s2、s3和s4都 可以是复合语句。if…elseif…else语句执行结果如图3.3所示。 图3.3 if…elseif…else语句执行结果 例3.4 下面是使用if…elseif…else语句的简单例子。输出结果为“Xis20”。源程 序代码如下所示: public class exp3_4{ public static void main(String args[]){ ·49· int x=20; if(x==5){System.out.print("X is 5");} else if(x==15){System.out.print("X is 15");} else if(x==25){System.out.print("X is 25");} else{System.out.print("X is:"+x); } } } 说明:程序使用了多分支if…elseif…else语句进行多个条件的判断,并在最后使用 了else语句来对多分支选择语句进行补充。如果传入的初始化值满足其中的elseif语 句,则会跳过执行其他的elseif以及else语句。要注意if…elseif…else语句中最多只能 有一个else语句。 3.2.4 嵌套的if…else语句 嵌套的if…else语句是指可以在另一个if或者elseif语句中使用一个或者多个的if 或者elseif语句。在嵌套的语句中最好给语句加上花括号,以提高代码的可读性。其语 法格式为: if(条件1){ if(条件2){ s1 语句 }else{ s2 语句 } }else{ if(条件3){ s3 语句 }else{ s4 语句 } } 图3.4 嵌套使用if…else 语句执行结果 例3.5 下面是一个嵌套使用if…else语句与if…else if…else语句构造多分支程序的例子,判断某一年是否为闰年。 闰年的条件是符合下面二者之一:能被4整除,但不能被100 整除;能被4整除,又能被100整除。输出结果如图3.4所示。 public class exp3_5 { public static void main(String args[]) { boolean leap; int year=2008; //方法1 if ((year%4==0 && year%100!=0)||(year%400==0)) System.out.println(year+"年是闰年"); else System.out.println(year+"年不是闰年"); ·50· //方法2 year=2020; if (year%4!=0) leap=false; else if (year%100!=0) leap=true; else if (year%400!=0) leap=false; else leap=true; if (leap==true) System.out.println(year+"年是闰年"); else System.out.println(year+"年不是闰年"); //方法3 year=2050; if (year%4==0) { if (year%100==0) { if (year%400==0) leap=true; else leap=false; } else leap=false; } else leap=false; if (leap==true) System.out.println(year+"年是闰年"); else System.out.println(year+"年不是闰年"); } } 说明:方法1用一个逻辑表达式包含了所有的闰年条件;方法2使用了多分支选择 语句(if…elseif…else语句);方法3通过花括号({})对if…else进行匹配来实现闰年的 判断。大家可以根据程序对比这3种方法,体会其中的联系和区别,在不同的场合选用适 当的方法。 3.2.5 开关语句(switch语句) 可以看出,虽然嵌套的条件语句可实现多个分支处理,但嵌套太多时容易出错和混 乱,这时可以使用开关语句switch处理。使用它可以容易地写出判断条件,特别是有很 多条件选项的时候。 开关语句switch的语法格式为: switch(表达式) { case 常量1: 语句1; break; case 常量2: 语句2; break; ... default: ·51· 语句n; } 其中,switch、case、default是关键字,default子句可以省略。开关语句先计算条件的值, 然后将条件的值与各个常量比较,如果条件值与某个常量相等,就执行该常量后面的 图3.5 switch语句执行结果 语句;如果都不相等,就执行default下面的语句。 如果无default子句,就什么都不执行,直接跳出开 关语句。 使用开关语句时,注意以下几点: (1)case后面的常量必须是整数或字符型,即 int、short、byte和char类型,而且不能有相同的值。 (2)switch语句可以拥有多个case语句。每个 case后面跟一个要比较的值和冒号。 (3)通常在每一个case中都通过break语句提 供一个出口,使流程跳出开关语句。否则,在第一个 满足条件case后面的所有语句都会被执行,这种情 况叫作落空。 (4)switch语句可以包含一个default分支,该 分支必须是switch语句的最后一个分支。default在 没有case 语句的值和变量值相等的时候执行。 default分支不需要break语句。 switch语句执行结果如图3.5所示。 例3.6 switch语句的使用,有break语句。本 程序当温度变量c小于10℃时,显示“有点冷”;c小 于25℃时,显示“正合适”;c小于35℃时,显示“有点热”;c大于或等于35℃时,显示“太热 了”。下面的源程序输出结果为“28℃ 有点热”。 public class exp3_6 { public static void main(String args[]) { int c=28; switch(c<10? 1:c<25? 2:c<35? 3:4) { case 1: System.out.println(" "+c+"℃ 有点冷"); break; case 2: System.out.println(" "+c+"℃ 正合适"); break; case 3: System.out.println(" "+c+"℃ 有点热"); break; default: ·52· System.out.println(" "+c+"℃ 太热了"); } } } 例3.7 switch语句的使用,无break语句。输出结果如图3.6所示。 public class exp3_7 { public static void main(String args[]) { int c=28; switch(c<10? 1:c<25? 2:c<35? 3:4) { case 1: System.out.println(" "+c+"℃ 有点冷"); case 2: System.out.println(" "+c+"℃ 正合适"); case 3: System.out.println(" "+c+"℃ 有点热"); default: System.out.println(" "+c+"℃ 太热了"); } } } 图3.6 无break语句的结果 说明: 通过这两个例子可以看出break语句的作用。例3.7由 于缺少break语句,使得程序执行完case3下面的语句,紧接 着又执行了default下面的语句。 因为case后面的常量必须是整数或字符型,这两个程序采用了转换方法,将判断条 件的取值最终转换为数值,请读者自行分析三元运算符(c<10?1:c<25?2:c<35?3:4)的 作用。 3.2.6 在switch语句中应用枚举类型 例3.8 switch语句与枚举操作的使用。输出结果如图3.7所示。 public class exp3_8 { public enum Season {SPRING, SUMMER, AUTUMN, WINTER;} public static void viewSeason(Season season) { switch(season) { case SPRING: System.out.println("[春天,枚举常量:"+season.name()+"]"); break; case SUMMER: System.out.println("[夏天,枚举常量:"+season.name()+"]"); break; case AUTUMN: ·53· System.out.println("[秋天,枚举常量:"+season.name()+"]"); break; case WINTER: System.out.println("[冬天,枚举常量:"+season.name()+"]"); break; } } public static void main(String[] arg) { viewSeason(Season.SPRING); viewSeason(Season.SUMMER); } } 图3.7 switch语句与枚 举操作的使用 说明: (1)从本例可以看出,在类ViewSeason中也可以声明枚举 类型Season。 (2)从本例可以看出,在switch语句中应用枚举简洁又方便。 (3)通过“枚举名.常量名”方式可以调用枚举中的常量,例如,本例Season.SPRING 调用Season枚举类中的静态常量SPRING。 3.3 循环语句 到目前为止,我们看到的都是线性的程序,即每行命令只有一次执行的机会(选择语 句则会忽略若干行)。能否重复执行一些语句呢? 利用循环语句可以解决这个问题。循 环可使程序根据一定的条件重复执行某一部分程序语句,直到满足终止循环条件为止。 本节主要介绍Java的3 种循环语句:确定次数循环(for)、先判定后执行循环 (while)和先执行后判定循环(do…while)的使用方法。 3.3.1 确定次数循环语句(for循环) 如果希望程序的一部分内容按固定的次数重复执行,可使用for循环。for循环采用 图3.8 逆序输出数组 一个计数器控制循环次数,每循环一次计数器就加1,直到完 成给定的循环次数为止。 例3.9 该程序利用for循环语句为一维数组中的每个元 素赋值,然后按逆序输出,结果如图3.8所示。 public class exp3_9 { public static void main(String args[]) { int i; int a[]=new int[5]; for (i=0; i<5; i++) a[i]=i; for (i=a.length-1; i>=0; i--) System.out.println("a["+i+"]="+a[i]); ·54· } } 例3.10 按5度的增量打印出一个从摄氏度到华氏度的转换表,输出结果如图3.9 所示。 class exp3_10 { public static void main (String args[]) { int fahr,cels; System.out.println("摄氏度 华氏度"); for (cels=0; cels<=40; cels+=5) { fahr=cels*9/5+32; System.out.println(" "+cels+" "+fahr); } } } 说明: 从上面的例子中归纳出for循环的语法格式为: for(初始化语句; 循环条件; 迭代语句){ 语句序列 } (1)初始化语句用于初始化循环体变量;循环条件用于判断是否继续执行循环体,其 值是boolean型的表达式,即结果只能是true或false;迭代语句用于改变循环条件的语 句;语句序列称为循环体,当循环条件的结果为true时,循环体将重复执行。 (2)for循环语句的流程首先执行初始化语句,然后判断循环条件,当循环条件为 true时,就执行一次循环体,最后执行迭代语句,改变循环变量的值。这样就结束了一轮 循环。接下来进行下一次循环(不包括初始化语句),直到循环条件的值为false时才结束 循环。for循环语句执行过程如图3.10所示。 图3.9 摄氏度到华氏度的转换表 图3.10 for循环语句执行过程 ·55· (3)初始化语句中的变量初始化可在for语句之前定义,也可在循环括号中定义。迭 代语句常写成增量运算的形式,以加快运算速度。根据需要,增量可以是1,也可以大于 1。增量计算也可以放在循环体中进行,即把迭代语句移到循环体内的适当位置,原位置 为空。 (4)使用循环语句时常常会遇到死循环的情况,就是无限制地循环下去。所以在使 用for循环时,要注意初值、终值和增量的搭配。终值大于初值时,增量应为正值,终值小 于初值时,增量应为负值。编程时必须密切关注计数器的改变,这是实现正常循环避免陷 入死循环的关键。例如下面的for循环: for(int i=0;i>=0;i++){ System.out.println("value of i :"+i) } 上述for循环,由于初始化“i=0”,满足循环条件,当循环每执行一次“i++”,i就会 增加1,永远满足循环条件,因此循环永远不会终止,程序陷入死循环。 3.3.2 foreach 循环语句 foreach语句为数组或对象集合中的每个元素重复一个嵌入语句组。foreach语句是 图3.11 for与foreach语句 遍历数组 for语句的特殊简化版本,任何的foreach语句都可以改写为 for语句版本,但是foreach语句并不能完全取代for语句。 例3.11 这个程序将通过for语句和foreach语句实现数 组的遍历,输出结果如图3.11所示。 public class exp3_11 { public static void main(String[] args) { int[] intary={1,2,3,4}; //声明数组intary forDisplay(intary); foreachDisplay(intary); } public static void forDisplay(int[] a){ System.out.println("使用for 循环数组"); for(int i=0; i=0){ System.out.println("value of i :"+i) } 上述while循环,由于初始化i=0,永远满足条件i>=0,因此循环永远不会终止,运 行后程序会一直输出“valueofi:0”,程序陷入死循环。 3.3.4 先执行后判定循环语句(do…while循环) do…while循环与while循环相反,被称为后测试循环语句,其是先执行循环体中的 语句,再计算while后面的条件,若条件值为false则跳出循环,否则继续下一轮循环。 什么时候使用do…while循环呢? 有些情况下,不管条件的值是true还是false,都 希望把指定的语句至少执行一次,那么就应使用do…while循环,看下面的例子。 例3.13 求1+2+…+100的值,输出结果为“1+2+…+100=5050”,源程序代码 如下所示: class exp3_13 { public static void main(String args[]) { int n=1; int sum=0; do sum+=n++; while (n<=100); System.out.println("1+2+…+100="+sum); } } 说明: (1)归纳do…while循环的语法格式为: do {循环体} while (条件); 图3.14 do…while语句执行过程 其中,do、while是关键字。程序首先执行do下面的循 环体,然后计算while后面条件的值,如果其值为true, 则重复执行循环体,否则,结束循环。do…while语句执 行过程如图3.14所示。 (2)与while循环相同,do循环在循环体中也一定 要有改变条件值为false的语句,否则会陷入死循环。 ·58· 例如下面的do…while循环: int i=0; do{ System.out.println("value of i :"+i); }while(i>=0); 上述do…while循环,由于初始化i=0,永远满足条件i>=0,因此循环永远不会终 止,运行后程序会一直输出“valueofi:0”,程序陷入死循环。do…while循环控制并不是 很常用,但有时却非常重要,使用时特别注意不要忘记了while语句结尾处的分号(;)。 3.3.5 嵌套使用循环语句 嵌套使用循环语句就是在一个循环体内又包含另一个完整的循环结构,而在这个完 整的循环体内还可以嵌套其他的循环结构。例如while循环语句嵌套、while循环语句与 for循环语句嵌套等,看下面的例子。 例3.14 分别用while循环语句与for循环语句嵌套实现累计求和,程序运行结果如 图3.15所示。 public class exp3_14 { public static void main(String args[]) { int n=10, sum=0; while (n>0) { //while 循环 sum=0; for (int i=1; i<=n; i++) sum+=i; //for 循环 System.out.println("前"+n+"个数的总和为:"+sum); n--; //改变计数器的值 } } } 图3.15 累计求和结果 说明:程序使用了while循环语句与for循环语句嵌套,对 n和sum 初始化并赋值,while循环判断n>0值为true,执行 while内嵌套的for循环语句,向屏幕输出前n个数的总和值。 3.3.6 循环语句小结 一个循环一般应包括以下4部分内容。 (1)初始化部分:用来设置循环的一些初始条件,计数器清零等。 (2)循环体部分:这是反复被执行的一段代码,可以是单语句,也可以是复合语句。 (3)迭代部分:这是当前循环结束,下一次循环开始时执行的语句,常用来使计数器 加1或减1。 (4)终止部分:通常是描述条件的逻辑表达式或关系表达式,每一次循环要对该表 达式求值,以验证是否满足循环终止条件。 ·59· 3.4 跳转语句 跳转语句可以无条件改变程序的执行顺序。 本节的内容主要介绍Java的3种跳转语句:break语句、continue语句和return语 句的使用方法。 3.4.1 break语句 break语句提供了一种方便地跳出循环的方法,用其可以立即终止循环,跳出循环 体。它在for、while或do…while循环中,有强制终止循环的作用,在switch语句跳出该 语句,继续执行其他语句。 例3.15 break语句的使用。输出结果如图3.16所示。 class exp3_15{ public static void main(String args[]) { boolean test=true; int i=0; while (test) { i=i+2; System.out.println("i="+i); if (i>=10) break; } System.out.println("i 为"+i+"时循环结束"); } } 图3.16 break语句的使用 说明:执行这个程序时,尽管while条件的值始终为真, 但实际上只循环了5次。这是因为当i大于或等于10时遇到 了break语句,使流程跳出了循环。 3.4.2 continue语句 continue语句只能用在循环结构中,它跳过循环体中尚未执行的语句,重新开始下一 轮循环,从循环体第一个语句开始执行。在for循环中,continue语句使程序立即跳转到 更新语句。在while或者do…while循环中,程序立即跳转到布尔表达式的判断语句。下 面通过一个例子来说明它的使用方法。 例3.16 下面的程序可以输出1~9中除6以外所有偶数的平方值,输出结果如 图3.17所示。 class exp3_16 { public static void main(String args[]) { for (int i=2;i<=9;i+=2) { if (i==6) continue; ·60· System.out.println(i+"的平方="+i*i); } } } 图3.17 使用continue语句 说明:程序采用for循环,int数据类型i从2开始进行 for循环,每次计数器加2,当i值为6时执行continue语句, 跳过“System.out.println(i+" 的平方="+i*i);”语句,重 新开始下一轮循环。 3.4.3 带标号的continue语句 Java也支持带标号的continue语句,它通常用在嵌套循环的内循环中,可以用标号 标出想跳到的那条语句继续重复执行程序。它的语法格式为: 标识符: … continue 标识符; 例3.17 求100~200的所有素数。该例通过一个嵌套的for循环来实现,输出结果 如图3.18所示。 public class exp3_17 { 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.18 100~200的所有素数 ·61· 说明:程序中分别使用了continue语句和带标号的continue语句。在输出方法上分 别使用了系统的println方法和print方法,二者的区别在于前者输出时换行,后者输出时 不换行。 3.4.4 return语句 return语句用来返回方法的值,其通常位于一个方法体的最后一行,当程序执行到 return语句时,退出该方法并返回一个值,继续执行调用这个方法语句的下一条语句。 当方法用void声明时,说明不要返回值(即返回类型为空),return语句省略。 return语句格式为: return 表达式; 当程序执行return语句时,先计算“表达式”的值,然后将表达式的值返回到调用该 方法的语句。返回值的数据类型必须与方法声明数值类型一致,可使用强制类型转换使 类型一致。 例3.18 使方法具有返回值的return语句,输出结果如图3.19所示。 class exp3_18 { final static double PI=3.14159; public static void main(String args[]) { double r1=8.0, r2=5.0; System.out.println("半径为"+r1+"的圆面积="+area(r1)); System.out.println("半径为"+r2+"的圆面积="+area(r2)); } static double area(double r) { return (PI*r*r); } } 图3.19 带返回值的方法 说明:程序中定义了一个double数据类型具有返回值 的area方法,通过return语句给area返回值(PI*r*r)。 在main方法中,调用了area方法,输出了圆面积的数 值。area方法的功能就像函数一样,通过area方法的参数指定一个半径的值,area方法 得到一个面积值。 3.5 知识拓展———注解 注解是JDK1.5及以后版本引入的一个特性,与类、接口、枚举在同一个层次。它可 以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明, 注释。本节主要介绍Java提供的内置注解、元数据注解与自定义注解。 ·62· 3.1 注解概述 5. 注解(Annotation)也叫元数据,是一种代码级别的说明,其实就是代码里的特殊标 记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理,通过使用注解,可以 在不改变原有程序逻辑的情况下,在源文件中嵌入一些补充信息,通过反射机制编程可以 实现对这些元数据(用来描述数据的数据)的访问(第5章介绍反射机制)。 javlnanttoAnoain是注解的接口, 接 aag.noain.ntto所有的注解都默认实现了此接口( 口的具体内(.) 容在第5章介绍)。注解不会直接影响程序的语义,只是作为注解(标识)存 在,另外,可以在编译时选择代码里的注解是否只存在于源代码级,或者在clas 文件、运 行时中出现(SOURCE/CLASS/RUNTIME )。 使用注解时要在其前面增加@符号,将注解当成一个修饰符使用,用于修饰它支持的 程序元素,在代码中的使用方式为“@注解名”。 根据注解参数的个数,可以将注解分为标记注解、单值注解、完整注解三类。根据注 解的作用,可以将注解分为内置注解、元数据注解(或称元注解)与自定义注解三类。 5.内置注解与元注解 3.2 1.内置注解 在JDK5.0之后,a内置了三种注解,可以在Ja程序中直接使用,将其当成一个 修饰符来使用,用于修饰它支持的程序元素。 Javav (1)@Overide用于限定重写父类方法,该注解只能用于方法。 (2)@Deprecated用于表示某个程序元素(类,方法等)已过时。如果在其他程序中 使用了此元素,则在编译时将出现警告信息。 (3)@SuppresWarnings用于压制警告信息的出现。 2.元注解 元注解的作用是用于修饰其他注解定义。JDK5.ta 0定义了4个标准的meannotation元注解类型。 (1)@Target。用于描述注解的使用范围,表示该注解用于什么地方,未标注则表示 该注解可用于所有的地方,可能范围值在枚举类ElemenetType中,包括: ElemenetType. CONSTRUCTOR:构造器 。 ElemeetTyp.ELD:域( n neFI包括eum实例) 。 ElemenetTypeLOCAL_VARIABLE:局部变量 。 ElemenetType.M(.) ETHOD:方法 。 ElemeeePA ntTyp.CKAGE:包 。 ElemeeePARAMETER:参数 。 ntTyp. ElemenetType. n TYPE:类,接口(包括注解类型)或eum声明。 (2)@Retention。用于描述注解在什么级别保存其信息,即注解的生命周期 ·36· 。可选 的参数值在枚举类型RetentionPolicy中,包括: RetentionPolicy.SOURCE:注解直接被编译器丢弃。 RetentionPolicy.CLASS:编译器把注解记录在class文件中。当运行Java程序时, JVM 不会保留注解。这是默认值。 RetentionPolicy.RUNTIME:编译器把注解记录在class文件中。当运行Java程序 时,JVM 会保留注解。程序可以通过反射获取该注解。 (3)@Documented。用于描述修饰的注解将被javadoc工具提取成文档。此注解不 常用,了解即可。 (4)@Inherited。用于描述允许子类继承父类中的注解。如果一个使用了@Inherited 修饰的annotation类型被用于一个类,则这个annotation将被用于该类的子类。此注解 不常用,了解即可。 例3.19 本例说明如何在类中使用内置注解。 public class exp3_19 { public String name; public int age; @Deprecated //表示不建议使用prin()方法,调用时会出现删除线 public void prin(String name) { System.out.println(name); } @Override //限定重写父类Object 的toString()方法,否则会报编译错误 public String toString() { return "Person [name="+name+", age="+age+"]"; } public static void main(String[] args) { exp3_19 person=new exp3_19 (); person.prin(""); //因pin()方法加有@Deprecated 注解,故方法名上有横线, //表明此方法已过时,不建议使用 @SuppressWarnings("unused") int i; //因为变量i 在程序中没有被使用,因此处有注解,不会有警告 int j; //变量j 在程序中没有被使用,但没有使用@SuppressWarnings("unused") //注解,此处会有警告信息 } } 说明:本例旨在说明如何在类中使用内置注解。 (1)使用@Override注解,覆盖的方法一定要是其父类的方法,否则在Eclipse中会 出现编译错误。 (2)调用由@Deprecated注解的方法时,在Eclipse中会出现person.prin(""); 警示提示。 (3)变量j在程序中没有被使用,又没有使用@SuppressWarnings("unused")注解, ·64·