目录
1 类的方法概述
1.1 什么是类的方法
类是由一组具有相同属性和共同行为的实体抽象而来的。对象执行的操作是通过编写类的方法实现的。显而易见,类的方法是一个功能模块,其作用是"做一件事情"。例如,在童年时代,大家可能玩过电动玩具。图12.1所示是一只"电动玩具狮子",在它身上有两个按钮,如果按动按钮,电动狮子就会跑或叫。
图12.1电动玩具狮子
下面就创建一个电动狮子(AutoLion)类,它的属性和行为如示例1所示。
示例1
package cn.jbit.dlc1;
public class AutoLion2 {
String color = "黄色";
//跑方法
public void run() {
System.out.println("正在以0.1米/秒的速度向前奔跑。");
}
//叫方法
public void cry() {
System.out.println("大声吼叫!");
}
//抢球方法
public String robBall() {
String ball = "球";
return ball;
}
}
在示例1中,AutoLion类定义了三个行为(方法):跑、叫和抢球。在玩电动玩具时,只要按动 "奔跑" 按钮,电动狮子就能跑,但是它为什么能跑呢?其实,它为什么能跑是生产电动狮子的厂商要思考的问题,我们不需要知道电动狮子的内部构造,只要按动这个按钮就可以了。电动狮子能跑能叫的内部实现就相当于类中的方法,这样的优点正是类提供给我们的。
类的每一个方法都实现了一个功能。例如,第11章编写的showcenter()方法,它的作用就是输出中心的信息,创建类的对象之后,可以直接调用这个方法,而不再去考虑这个方法是如何实现的。同样,对于示例1定义的run()、cry()和robBall ()方法,也可以直接调用。可见,类的方法定义了类的某种行为(功能),而且方法的具体实现封装在类中,实现了信息隐藏。
1.2 如何定义类的方法
类的方法必须包括以下三个部分。
- 方法的名称。
- 方法的返回值类型。
- 方法的主体。
语法:
public 返回值类型 方法名() {
//方法的主体
}
通常,编写方法时,分两步完成。
第一步:定义方法名和返回值类型。
第二步:在中编写方法的主体部分。
在编写方法时,要注意以下三点。
- 方法体放在一对大括号中。方法体就是一段程序代码,完成一定的工作。
- 方法名主要在调用这个方法时使用。在Java中一般采用骆驼式命名法。
- 方法执行后可能会返回一个结果,该结果的类型称为返回值类型。使用return语句返回值。
语法:
return表达式;
例如,在robBall() 方法中,返回值类型是String,因此在方法体中必须使用return返回一个字符串。
如果方法没有返回值,则返回值类型为void。例如,run()和cry()方法没有返回值,所以返回值类型为void。
因此,在编写程序时一定要注意方法声明中返回值的类型和方法体中真正返回值的类型是否匹配。如果不匹配,编译器就会报错。
其实这里的return语句是跳转语句的一种,它主要做两件事情。
- 跳出方法。意思是 "我已经完成了,要离开这个方法"。
- 给出结果。如果方法产生一个值,这个值放在return后面,即<表达式〉部分,意思是"离开方法,并将<表达式〉的值返回给调用它的程序"。就像我们按动按钮,电动狮子就会跑,这个"跑"就是方法返回的一个结果。
1.3 方法调用
定义了方法就要拿来使用。例如,在第11章我们定义了 showCenter()方法,用来输出相关信息。简单地说,在程序中通过使用方法名称从而执行方法中包含的语句,这一过程就称为方法调用。方法调用的一般形式如下。
语法:
对象名.方法名();
Java中类是程序的基本单元。每个对象需要完成特定的应用程序功能。当需要某一对象执行一项特定操作时,通过调用该对象的方法来实现。另外,在类中,类的不同成员方法之间也可以进行相互调用。接下来,就来分析下面的问题。
问题:小明过生日,爸爸送给他一个电动狮子玩具,编写程序测试这个狮子能否正常工作(能跑、会叫、显示颜色)。
分析:现在要模拟玩电动狮子的过程。按动控制狮子叫的按钮,它就会发出叫声;按动控制狮子跑或抢球的按钮,狮子就会奔跑或抢球。因此,根据要求,需要定义两个类:电动狮子类 ( AutoLion) 和测试类 (TestLion)。其中,TestLion类中定义程序入口 ( main()方法),检测跑和叫的功能是否可以正常运行。
示例2
电动狮子类:
package cn.jbit.dlc1;
/*
* AutoLion.java
* 电动玩具类
*/
public class AutoLion {
String color = "黄色"; // 颜色
/*
* 跑
*/
public void run() {
System.out.println("正在以0.1米/秒的速度向前奔跑。");
}
public String robBall() {
String ball = "球";
return ball;
}
/*
* 获得颜色
*/
public String getColor() {
return color;
}
/*
* 显示狮子特性
*/
public String showLion() {
return "这是一个" + getColor() + "的玩具狮子!";
// 另一种方式
//return "这是一个" + color + "的玩具狮子!";
}
}
测试类:
public class TestLion {
public static void main(String[] args) {
AutoLion lion = new AutoLion(); //创建AutoLion对象
String info=lion.showLion(); //调用方法并接收方法的返回值
System.out.println(info); //显示类信息
lion.run(); //调用跑方法
System.out.println("抢到一个" + lion.robBall()); //调用其抢球方法
}
}
程序运行结果如图12.2所示。
图12.2示例2的运行结果
在示例2中可以看到,类的成员方法相对独立地完成了某个应用程序功能,它们之间可以相互调用,调用时仅仅使用成员方法的名称。在本示例中,方法getColor()的功能是获得电动狮子的颜色,在showLion()方法中可以直接调用。
return "这是一个" + getColor() + "的玩具狮子!";
showLion()是类的成员方法,因此它可以直接调用这个类的另一个成员方法getColor(),调用时直接引用方法的名称getColor()就可以了。
但是,其他类的方法要调用AutoLion类的成员方法时,就必须首先创建这个类的一个对象,然后才能通过操作符使用它的成员方法。
AutoLion lion = new AutoLion(); //创建AutoLion对象
lion.run(); //调用跑方法
如果类的方法有返回值,调用时便可以得到它的返回值。例如:
String info=lion.showLion(); //调用方法并接收方法的返回值
System.out.println("抢到一个" + lion.robBall()); //调用其抢球方法
showLion()方法的返回值类型是String,可以用一个String类型的变量info来接收它的返回值。robBall()方法的返回值类型也是String,代码中将调用之后得到的返回值直接在控制台输出。对于有返回值的方法,这两种处理返回值的方式都是常见的。
总之,凡涉及类的方法的调用,均使用如下两种形式。
- 同一个类中的方法,直接使用方法名调用该方法。
- 不同类的方法,首先创建对象,再使用"对象名.方法名()"来调用。
1.4 常见错误
在编写方法及调用方法时,一定要细心,避免出现以下错误。
常见错误1
package cn.jbit.classandobject;
public class Student1{
public void showInfo(){
return "我是一名学生";
}
}
原因分析:方法的返回值类型为void,方法中不能有return语句。
常见错误2
package cn.jbit.classandobject;
public class Studen2{
public double getInfo(){
double weight = 95.5;
double height = 1.69;
return weight, height;
}
}
原因分析:方法不能返回多个值。
常见错误3
package cn.jbit.classandobject;
public class Student3{
public String showInfo(){
return "我是一名学生";
public double getInfo(){
double weight = 95.5;
double height = 1.69;
return weight;
}
}
}
原因分析:多个方法不能相互嵌套定义。例如,不能将方法getlnfo()定义在方法showinfo()中。
常见错误4
package cn.jbit.classandobject;
public class Student4{
int age = 20;
if(age<20){
System.out.println("年龄不符合入学要求!");
}
public void showInfo(){
return "我是一名学生";
}
}
原因分析:不能在方法外部直接写程序逻辑代码。
2变量的作用域
在现实生活中,大家经常会碰到这样一种情况:身边的一些资源无权使用。
- 互联网上的一些宝贵的资料我们无权下载——因为我们不是会员。
- 某公司的研发中心我们不能自由出入——因为我们不是该公司的研发人员。
- 高级俱乐部的豪华高尔夫球场我们不能去玩——因为我们没有 vip 卡。
- 比尔•盖茨家的豪华游泳池我们无权使用——因为我们不是主人或者没有被邀请。当然,普通的公共游泳池大家可以自由使用。
可见,一些资源仅仅能被授权的人使用。如果不在授权范围内,就无权享用。在Java中,也会遇到同样的情况。
2.1 成员变量和局部变量
Java中以类来组织程序,类中可以定义变量和方法,在类的方法中,同样也可以定义变量。在不同的位置定义的变量有什么不同吗?
如图12.4所示,在类中定义的变量称为类的成员变量,如变量1、变量2和变量3。在方法中定义的变量称为局部变量,如变量4和变量5。在使用时,成员变量和方法的局部变量具有不同的使用权限。对于图12.4中AutoLion类所定义的变量说明如下。
- 成员变量:AutoLion类的方法可以直接使用该类定义的成员变量。如果其他类的方法要访问它,必须首先创建该类的对象,然后才能通过操作符来引用。
局部变量:它的作用域仅仅在定义该变量的方法内,因此只有在这个方法中能够使用。
图12.4变量作用域
总的来说,使用成员变量和局部变量时需要注意以下几点内容。
- 作用域不同。局部变量的作用域仅限于定义它的方法,在该方法外无法访问。成员变量的作用域在整个类内部都是可见的,所有成员方法都可以使用,如果访问权限允许,还可以在类外部使用成员变量。
- 初始值不同。对于成员变量,如果在类定义中没有给它赋初始值,Java会给它一个默认值,基本数据类型的值为0,引用类型的值为null。但是Java不会给局部变量赋初始值,因此局部变量必须要定义赋值后再使用。
- 在同一个方法中,不允许有同名的局部变量。在不同的方法中,可以有同名的局部变量。
- 局部变量可以和成员变量同名,并且在使用时,局部变量具有更高的优先级。
2.2 常见错误
在编程过程中,因为使用了无权使用的变量而造成编译错误是非常常见的现象,阅读下面的几段常见错误代码,引以为戒。
1. 误用局部变量
常见错误5
package cn.jbit.classandobject;
public class Student {
int score1 = 88;
int score2 = 98;
public void calcAvg(){
int avg = (score1 + score2)/2;
}
public void showAvg(){
System.out.println("平均分是: " + avg);
}
}
如果编写一个main()方法来调用Student类的showAvg()方法,大家会发现编译器会报错"无法解析avg"。这是为什么呢?因为在方法showAvg()中使用了在方法calcAvg()中定义的变量avg,这超出了 avg的作用域。
排错方法:如果要使用在方法calcAvg()中获得的avg结果,可以编写带有返回值的方法,然后从方法showAvg()中调用这个方法,而不是直接使用在这个方法中定义的变量。
2. 控制流语句块中的局部变量
常见错误6
public class VariableDomain1 {
public static void main(String[] args) {
for (int a = 0; a < 4; a++ ) {
System.out.println("Hello!");
}
System.out.println(a);
}
}
编译运行代码,编译器会报错"无法解析a"。这又是什么原因呢?仔细观察就会发现,变量a是在for循环块中定义的变量,因此a只能在for循环中使用,一旦退出循环,就不能再使用a 了。另外,在while循环、do-while循环、if选择结构、switch选择结构中定义的变量,作用域也仅仅在这些控制流语句块内。注意:这是程序初学者非常容易犯的错误,大家一定要提高警惕。
3 面向对象编程
学习了类的概念及类的成员方法,那么,Java这种面向对象的编程方法到底带给了我们什么呢?
3.1 如何使用面向对象编程
面向对象编程 ( Object Oriented Programming, OOP)是一种计算机编程架构,是20世纪90年代才流行起来的一种软件编程思想。OOP的一条基本原则就是计算机是由单个能够起到子程序作用的单元或对象组合而成的,采用这种架构编程主要起到重用性、灵活性和扩展性的强大作用。下面我们就来体会一下OOP。
在学习本章前,学员们已经能够在main()方法中实现计算学生总成缋、计算平均分、显示平均分及显示总成绩等功能,如示例3所示。
示例3
package cn.jbit.dlc1;
import java.util.Scanner;
public class OldScoreCalc {
public static void main(String[] args) {
/*接收成绩*/
Scanner input = new Scanner(System.in);
System.out.print("请输入 Java 成绩:");
int java = input.nextInt();
System.out.print("请输入 C# 成绩:");
int c = input.nextInt();
System.out.print("请输入 DB 成绩:");
int db = input.nextInt();
/*计算并显示输出*/
int total = java + c + db;
double avg = total / 3.0;
System.out.print("总成绩:" + total);
System.out.print("\n 平均分: " +avg);
}
}
设想一下,如果有100个类都要实现这个功能,示例3中的代码完全不能够重用,工作量会非常大。但是如果使用本章学习的面向对象的方法来实现,将独立的功能模块使用方法来实现,100个类都来调用就行了,如图12.5所示。
这就是面向对象的编程思想给大家带来的好处:类的方法可以实现某个特定的功能,其他的类不需要知道它是如何实现的。知道实现此功能的类和它的方法名,就可以直接调用,而不用重复编码。
学习方法
对面向对象思想的理解是一个过程,初学者需先模仿,学习教员是如何对一个问题进行分析的。随着知识的积累、动手操作能力的增强,逐步掌握使用面向对象思想分析问题及解决问题的思路。