方法
| 導航 語言基礎 主題: |
方法是與物件溝通的方式。當我們呼叫或執行方法時,意味著請求物件執行一項任務。可以說,方法實現了物件的“行為”。對於每個方法,都需要給定名稱、定義輸入引數和返回值型別。此外,還需要設定其 可見性(私有、受保護或公共)。如果方法丟擲檢查型異常,也需要進行宣告。這被稱為“方法定義”。方法定義的語法如下:
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.
- 要了解如何過載和覆蓋方法,請參閱 過載方法和建構函式。