在本章的开始提到,类通常由两个要素组成:实例变量和方法。方法是个很大的话题,因为Java 给他们如此大的功能和灵活性。事实上,下一章的大部分都用来介绍方法。然而,你现在需要学习一些基础以便你能开始把方法加到你的类中。
这是方法一般的形式:
type name(parameter-list) {
// body of method
}
其中,type 指定了方法返回的数据类型。这可以是任何合法有效的类型,包括你创建的类的类型。如果该方法不返回任何值,则它的返回值type 必须为void 。方法名由name 指定。除了被当前作用域中的其他项使用的标识符以外,方法名可以是任何合法的标识符。parameter-list (自变量列表)是一系列类型和标识符对,用逗号分开。自变量本质上是变量,它接收方法被调用时传递给方法的参数值。如果方法没有自变量,那么自变量列表就为空。
对于不返回void 类型的方法,使用下面格式的return语句,方法返回值到它的调用程序:
return value;
其中,value 是返回的值。接下来,你将看到怎样创建多种类型的方法,包括带参数的和那些有返回值的方法。
6.4.1 为Box类添加一个方法
尽管创建一个仅包含数据的类是相当不错的事情,但这样的情况很少发生。大部分情况是你将使用方法存取由类定义的实例变量。事实上,方法定义大多数类的接口。这允许类实现函数可以把内部数据结构的特定布局隐蔽到方法抽象后面。除了定义提供数据的存取的方法,你也可以定义被类的内部自己所使用的方法。
让我们由对Box 类增加一个方法开始。回顾一下前面计算盒子体积的例子,你会发现用Box 类有时会比使用BoxDemo 类能更好地处理这个问题。不管怎么说,一个盒子的体积依赖于盒子的大小,这就是我们想到用Box类来计算盒子的体积。为了做到这一点,你必须对Box类增加一个方法,示例如下:
// This program includes a method inside the box class.
class Box { double width; double height; double depth;
// display volume of a box void volume() { System.out.print("Volume is ");
System.out.println(width * height * depth);
}
}
class BoxDemo3 {
public static void main(String args[]) {
Box mybox1 = new Box();
Box mybox2 = new Box();
// assign values to mybox1's instance variables
mybox1.width = 10;
mybox1.height = 20;
mybox1.depth = 15;
/* assign different values to mybox2's
instance variables */
mybox2.width = 3;
mybox2.height = 6;
mybox2.depth = 9;
// display volume of first box
mybox1.volume();
// display volume of second box
mybox2.volume();
}
}
该程序产生的输出如下,与先前版本程序的输出一样。
Volume is 3000.0
Volume is 162.0
注意看下面两行程序:
mybox1.volume ();
mybox2.volume ();
该例的第一行调用mybox1 的volume() 方法。也就是,它使用对象名加点号运算符调用mybox1 对象的volume() 方法。这样,调用mybox1.volume( ) 显示mybox1 定义的盒子的体积,调用mybox2.volume ()将显示mybox2 定义的盒子的体积。每次调用volume() ,它都会显示指定对象的体积。
如果你对方法调用的概念比较陌生,下列的讨论将有助于澄清该概念。当mybox1.volume ( ) 被执行时,Java 运行系统将程序控制转移到volume( ) 定义内的代码。当volume( ) 内的语句执行后,程序控制返回调用者,然后执行程序调用的下一行语句。Java 执行方法的过程类似于子程序的运行。
在volume() 方法中有一些需要注意的地方:实例变量width,height 和depth 被直接引用,并没有在它们前面加对象名或点号运算符。当一个方法使用由它的类定义的实例变量时,它可以直接这样做,而不必使用显式的对象引用和使用点号运算符。这是很容易理解的。一个方法总是被它的类的对象调用。只要这个调用过程一发生,对象就是可见的。因此,在方法中就没有必要二次指定对象了。这意味着,volume() 中的width,height 和depth 已经隐含地引用了调用volume() 方法中的这些变量的拷贝。
让我们复习一下:当一个实例变量不是被该实例变量所在类的部分代码访问时,它必须通过该对象加点运算符来访问。但是当一个实例变量被定义该变量的类的代码访问时,该变量可以被直接引用。同样的规则也适用于方法。
6.4.2 返回值
执行volume() 方法确实将计算盒子体积的值返回到Box类,但这并不是最好的方法。例如,你的程序的其他部分如何知道一个盒子的体积,而不显示它的值?一个更好地实现 volume() 的方法是将它计算的盒子体积的结果返回给它的调用者。下面的例子是对前面程序的改进,它正是这样做的:
// Now,volume() returns the volume of a box.
class Box { double width; double height; double depth;
// compute and return volume double volume() { return width * height * depth;}}
class BoxDemo4 {
public static void main(String args[]) {
Box mybox1 = new Box();
Box mybox2 = new Box();
double vol;
// assign values to mybox1's instance variables
mybox1.width = 10;
mybox1.height = 20;
mybox1.depth = 15;
/* assign different values to mybox2's
instance variables */
mybox2.width = 3;
mybox2.height = 6;
mybox2.depth = 9;
// get volume of first box
vol = mybox1.volume();
System.out.println("Volume is " + vol);
// get volume of second box
vol = mybox2.volume();
System.out.println("Volume is " + vol);
}
}
在这个程序中,当volume() 被调用时,它被放在赋值语句的右边。左边是接收volume() 返回值的变量。因此,当下面的语句执行后,
vol = mybox1.volume();
变量mybox1.volume ( ) 的值是 3,000,且该值被保存在vol 中。
对于返回值的理解,要注意下面两件重要的事情:
?
方法返回的数据类型必须与该方法指定的返回类型相兼容。例如,如果一个方法的返回值是布尔型,就不可能返回整数。
?接收方法返回值的变量
(例如本例中的变量 vol) 也必须与指定方法返回值的类型相兼容。
另外一点:因为实际上不需要vol 变量,前面的程序可以被写得更高效一些。对volume( ) 方法的调用可以直接用在println ( ) 语句中,如下面的语句:
System.out.println("Volume is " + mybox1.volume());
在本例中,当println ( ) 被执行时,mybox1.volume ( ) 将自动地被调用,而且它的值会被传递给println ( ) 。
6.4.3 加入带自变量的方法
大多数方法不需要自变量。自变量对方法没有特殊要求。也就是说,带自变量的方法,可以完成各种数据操作,它还可以用在很多有微妙差别的情况。为了说明这一点,让我们举一个非常简单的例子。下面的方法返回数字10的平方:
int square()
{ return 10 * 10;
}
运行该方法,确实返回了10 的平方的值,但它的使用是很有限的。然而,如下所示,如果你修改该方法,以便它带一个自变量,这样square( ) 就更有用了。
int square(int i)
{ return i * i;
}
现在,square() 可以返回任何调用它的值的平方。也就是说,square() 现在是可以计算任何整数值的平方的一个通用方法,而不单纯是数字10 。
下面是一个例子:
int x,y;x = square(5); // x equals 25x = square(9); // x equals 81y = 2;x = square(y); // x equals 4
在第一次调用square( ) 时,值5被传递给自变量i。在第二次调用时,i接收到值9。第三次调用时,将值传递给y,在本例中是 2 。如这些例子所示,square ( ) 可以返回传递给它的任何数据的平方。
区分自变量(parameter )和参数(argument )这两个术语是很重要的。自变量是方法定义的一个变量,当方法被调用时,它接收一个值。例如在square() 中,i就是一个自变量。参数是当一个方法被调用时,传递给该方法的值。例如,square(100) 把100 作为参数传递。在square()中,自变量i接收该值。
可以使用一个带自变量的方法来改进Box 类。在前面的例子中,每个盒子的尺寸不得不用单独的语句顺序的来设置,例如:
mybox1.width = 10;
mybox1.height = 20;
mybox1.depth = 15;
本例中的代码在执行时,它在两个方面比较麻烦。首先,它笨拙且容易发生错误。例如,很容易忘记设置其中的一个尺寸。其次,在设计的很好的Java 程序中,实例变量应该仅仅由定义类的方法来存取。在后面,你可以改变一个方法的行为,但是你不能改变一个暴露的实例变量的行为。
这样,设置一个盒子尺寸的更好的途径是创建一个自变量代表盒子尺寸的方法,而且适当地设置每个实例变量。下面的例子实现了这个想法。
// This program uses a parameterized method.
class Box { double width; double height; double depth;
// compute and return volume double volume() { return width * height * depth;}
// sets dimensions of box
void setDim(double w,double h,double d) {width = w; height = h;depth = d;
}
}
class BoxDemo5 {
public static void main(String args[]) {
Box mybox1 = new Box();
Box mybox2 = new Box();
double vol;
// initialize each boxmybox1.setDim(10,20,15);mybox2.setDim(3,6,9);
// get volume of first box
vol = mybox1.volume();
System.out.println("Volume is " + vol);
// get volume of second box
vol = mybox2.volume();
System.out.println("Volume is " + vol);
}
}
正如你看到的,setDim 方法用来设置每个盒子的尺寸,例如,当下面的语句执行后:mybox1.setDim(10,20,15);
10被拷贝进参数w,20被拷贝进h,15被拷贝进d。在setDim( ) 内的w、h、d的值分别赋给width 、height 和depth 。
许多读者,特别是那些有C/C++ 经验的读者,对前面章节中的概念会比较熟悉。但是,如果像方法调用、参数、自变量这些概念对你来说比较新的话,在继续学习以前,你要花些时间来练习。方法调用,自变量,返回值这些概念是Java 编程的基础。