方法
导航 语言基础 主题: ) |
方法是与对象沟通的方式。当我们调用或执行方法时,意味着请求对象执行一项任务。可以说,方法实现了对象的“行为”。对于每个方法,都需要给定名称、定义输入参数和返回值类型。此外,还需要设置其 可见性(私有、受保护或公共)。如果方法抛出检查型异常,也需要进行声明。这被称为“方法定义”。方法定义的语法如下:
MyClass {
...
public ReturnType methodName(ParamOneType parameter1, ParamTwoType parameter2) {
...
return returnValue;
}
...
}
可以使用 Java 关键字 void
声明方法不返回任何值。例如:
代码段 3.67:无返回值的方法。
private void methodName(String parameter1, String parameter2) {
...
return;
}
|
当方法不返回任何值时,方法结尾处的 return
关键字是可选的。当执行流程到达 return
关键字时,方法执行停止,执行流程返回到调用者方法。只要有办法执行下面的指令, return
关键字可以在方法中的任何位置使用
代码段 3.68:return 关键字位置。
private void aMethod(int a, int b) {
int c = 0;
if (a > 0) {
c = a;
return;
}
int c = c + b;
return;
int c = c * 2;
}
|
在 代码段 3.68 中,第 5 行的 return
关键字放置正确,因为当 a
为负数或等于 0 时,可以到达下面的指令。但是,第 8 行的 return
关键字放置错误,因为无法到达下面的指令。
问题 3.9:考虑以下代码
问题 3.9:编译器错误。
private int myMethod(int a, int b, boolean c) {
b = b + 2;
if (a > 0) {
a = a + b;
return a;
} else {
a = 0;
}
}
|
上面的代码将返回编译器错误。为什么?
答案 3.9:编译器错误。
private int myMethod(int a, int b, boolean c) {
b = b + 2;
if (a > 0) {
a = a + b;
return a;
} else {
a = 0;
}
}
|
该方法应该返回一个 int
类型的值,但当 a
为负数或等于 0 时,它什么也不返回。
参数传递
[edit | edit source]可以将任何 基本数据类型 或引用数据类型传递给方法。
基本类型参数
[edit | edit source]基本类型是“按值传递”的。这意味着,一旦基本类型被传递进去,方法内部的值与源变量之间就再没有联系了
代码段 3.69:修改变量的方法。
private void modifyValue(int number) {
number += 1;
}
|
|
|
正如在 代码段 3.70 中所看到的, modifyValue()
方法并没有修改 i
的值。
引用类型参数
[edit | edit source]对象引用是“按值传递”的。这意味着:
- 方法内部的引用与源引用之间不再有联系,
- 源对象本身和方法内部的对象本身仍然是同一个对象。
必须理解对象引用和对象本身之间的区别。对象引用是变量名与对象实例之间的链接
Object object ⇔ new Object() |
对象引用是一个指针,指向对象实例的地址。
对象本身是对象实例内属性的值
object.firstName | ⇒ | "James" |
object.lastName | ⇒ | "Gosling" |
object.birthDay | ⇒ | "May 19" |
查看上面的示例
代码段 3.71:修改对象的方法。
private void modifyObject(FirstClass anObject) {
anObject.setName("Susan");
}
|
|
|
姓名发生了变化,因为该方法修改了对象本身,而不是引用。现在,再看一下另一个示例
代码段 3.73:修改对象引用的方法。
private void modifyObject(FirstClass anObject) {
anObject = new FirstClass();
anObject.setName("Susan");
}
|
|
|
姓名没有发生变化,因为该方法修改了引用,而不是对象本身。该行为与方法被内联并且参数被分配给新的变量名时的行为相同
|
|
可变参数列表
[edit | edit source]Java SE 5.0 添加了对 可变参数列表 方法的语法支持,这简化了需要可变数量参数的方法的类型安全使用。非正式地说,这些参数被称为“varargs”[1]。可变参数的类型必须后跟 ...
,Java 会将所有参数打包成一个数组
代码段 3.76:使用 vararg 参数的方法。
public void drawPolygon(Point... points) {
//…
}
|
调用方法时,程序员只需用逗号分隔各个点,而无需显式创建 Point
对象的 数组。在方法内部,可以将各个点引用为 points[0]
、points[1]
等。如果没有传递任何点,则数组的长度为零。
一个方法既可以有普通参数,也可以有可变参数,但可变参数必须始终是最后一个参数。例如,如果程序员需要使用最小数量的参数,则这些参数可以在可变参数之前指定
代码段 3.77:可变参数。
// A polygon needs at least three points.
public void drawPolygon(Point p1, Point p2, Point p3, Point... otherPoints) {
//…
}
|
返回值参数
[edit | edit source]方法可以返回一个值(可以是基本类型或对象引用)。如果方法不返回值,则使用 Java 关键字 void
。
但是,一个方法只能返回一个值,那么如果要从一个方法中返回多个值怎么办?可以将一个对象引用传递给方法,让方法修改对象的属性,这样修改后的值就可以被视为方法的输出值。还可以创建方法内部的 Object 数组,将返回值分配给数组,并将数组返回给调用者。但是,如果要将基本数据类型和对象引用混合作为方法的输出值,这种方法就会产生问题。
有一个更好的方法,定义一个包含所需返回值的特殊返回值对象。在方法内部创建该对象,分配值,并将对该对象的引用返回给调用者。这个特殊对象“绑定”到这个方法,只用于返回值,所以不要使用公共类。最好的方法是使用嵌套类,请看下面的示例
代码清单 3.12:多个返回值变量。
public class MyObject {
...
/** Nested object is for return values from getPersonInfoById method */
private static class ReturnObject {
private int age;
private String name;
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setName(String name) {
name = name;
}
public String getName() {
return name;
}
} // End of nested class definition
/** Method using the nested class to return values */
public ReturnObject getPersonInfoById(int id) {
int age;
String name;
...
// Get the name and age based on the ID from the database
...
ReturnObject result = new ReturnObject();
result.setAge(age);
result.setName(name);
return result;
}
}
|
在上面的示例中, getPersonInfoById
方法返回一个对象引用,其中包含姓名和年龄的两个值。请看下面如何使用该对象
代码段 3.78:检索值。
MyObject object = new MyObject();
MyObject.ReturnObject person = object.getPersonInfoById(102);
System.out.println("Person Name=" + person.getName());
System.out.println("Person Age =" + person.getAge());
|
问题 3.10:考虑以下代码
问题 3.10:编译器错误。
private int myMethod(int a, int b, String c) {
if (a > 0) {
c = "";
return c;
}
int b = b + 2;
return b;
}
|
上面的代码将返回编译器错误。为什么?
答案 3.10:编译器错误。
private int myMethod(int a, int b, String c) {
if (a > 0) {
c = "";
return c;
}
int b = b + 2;
return b;
}
|
该方法应该返回一个 int
类型的值,但在第 4 行,它返回了 c
,这是一个字符串。
特殊方法,构造函数
[edit | edit source]构造函数是一个特殊方法,当使用 new
关键字创建对象时,它会自动调用。构造函数没有返回值,它的名称与类名相同。每个类都必须有一个构造函数。如果我们没有定义构造函数,编译器会自动创建一个称为“空构造函数”的默认构造函数。
代码清单 3.13:自动创建的构造函数。
public class MyClass {
/**
* MyClass Empty Constructor
*/
public MyClass() {
}
}
|
静态方法
[edit | edit source]静态方法是一种无需对象实例即可调用的方法。它可以直接在类上调用。例如,Integer
类的 valueOf(String)
方法就是一个静态方法
代码段 3.79:静态方法。
Integer i = Integer.valueOf("10");
|
static
关键字使属性与实例无关。这意味着无法引用单个对象的静态属性(因为这种特定对象的属性不存在)。相反,无论 JVM 中存在一个对象还是一百个对象,静态属性只有一个实例。以下是在静态方法中使用静态属性的示例
代码段 3.80:静态属性。
private static int count = 0;
public static int getNewInteger() {
return count++;
}
|
您可以注意到,当您使用 `System.out.println()` 时,`out` 是 `System` 类的一个静态属性。静态属性与类相关,而不是与任何对象实例相关。这就是 Java 实现一个通用输出流的方式,我们可以使用它来打印输出。以下是一个更复杂的用例
|
|
问题 3.11:访问 Oracle 的 `java.lang.Integer` 类 JavaDoc。
这个类有多少个静态字段?
4.
int MAX_VALUE
,int MIN_VALUE
,int SIZE
和Class<Integer> TYPE
.
- 要了解如何重载和覆盖方法,请参阅 重载方法和构造函数。