跳轉到內容

方法

100% developed
來自華夏公益教科書

導航 語言基礎 主題:v  d  e )


方法是與物件溝通的方式。當我們呼叫或執行方法時,意味著請求物件執行一項任務。可以說,方法實現了物件的“行為”。對於每個方法,都需要給定名稱、定義輸入引數和返回值型別。此外,還需要設定其 可見性(私有、受保護或公共)。如果方法丟擲檢查型異常,也需要進行宣告。這被稱為“方法定義”。方法定義的語法如下:

MyClass {
  ...
  public ReturnType methodName(ParamOneType parameter1, ParamTwoType parameter2) {
      ...
      return returnValue;
  }
  ...
}

可以使用 Java 關鍵字 void 宣告方法不返回任何值。例如:

Example 程式碼段 3.67:無返回值的方法。
private void methodName(String parameter1, String parameter2) {
  ...
  return;
}

當方法不返回任何值時,方法結尾處的 return 關鍵字是可選的。當執行流程到達 return 關鍵字時,方法執行停止,執行流程返回到呼叫者方法。只要有辦法執行下面的指令, return 關鍵字可以在方法中的任何位置使用

Warning 程式碼段 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:考慮以下程式碼

Example 問題 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;
  }
}

上面的程式碼將返回編譯器錯誤。為什麼?

答案
Example 答案 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]

基本型別是“按值傳遞”的。這意味著,一旦基本型別被傳遞進去,方法內部的值與源變數之間就再沒有聯絡了

Example 程式碼段 3.69:修改變數的方法。
private void modifyValue(int number) {
  number += 1;
}
Example 程式碼段 3.70:傳遞基本值給方法。
int i = 0;
modifyValue(i);
System.out.println(i);
Standard input or output 程式碼段 3.70 的輸出
0  

正如在 程式碼段 3.70 中所看到的, modifyValue() 方法並沒有修改 i 的值。

引用型別引數

[edit | edit source]

物件引用是“按值傳遞”的。這意味著:

  • 方法內部的引用與源引用之間不再有聯絡,
  • 源物件本身和方法內部的物件本身仍然是同一個物件。

必須理解物件引用和物件本身之間的區別。物件引用是變數名與物件例項之間的連結

Object objectnew Object()

物件引用是一個指標,指向物件例項的地址。

物件本身是物件例項內屬性的值

object.firstName "James"
object.lastName "Gosling"
object.birthDay "May 19"

檢視上面的示例

Example 程式碼段 3.71:修改物件的方法。
private void modifyObject(FirstClass anObject) {
  anObject.setName("Susan");
}
Example 程式碼段 3.72:傳遞引用值給方法。
FirstClass object = new FirstClass();
object.setName("Christin");

modifyObject(object);

System.out.println(object.getName());
Standard input or output 程式碼段 3.72 的輸出
Susan

姓名發生了變化,因為該方法修改了物件本身,而不是引用。現在,再看一下另一個示例

Example 程式碼段 3.73:修改物件引用的方法。
private void modifyObject(FirstClass anObject) {
  anObject = new FirstClass();
  anObject.setName("Susan");
}
Example 程式碼段 3.74:傳遞引用值給方法。
FirstClass object = new FirstClass();
object.setName("Christin");

modifyObject(object);

System.out.println(object.getName());
Standard input or output 程式碼段 3.74 的輸出
Christin

姓名沒有發生變化,因為該方法修改了引用,而不是物件本身。該行為與方法被內聯並且引數被分配給新的變數名時的行為相同

Example 程式碼段 3.75:內聯方法。
FirstClass object = new FirstClass();
object.setName("Christin");

// Start of the method
FirstClass anObject = object;
anObject = new FirstClass();
anObject.setName("Susan");
// End of the method

System.out.println(object.getName());
Standard input or output 程式碼段 3.75 的輸出
Christin

可變引數列表

[edit | edit source]

Java SE 5.0 添加了對 可變引數列表 方法的語法支援,這簡化了需要可變數量引數的方法的型別安全使用。非正式地說,這些引數被稱為“varargs[1]。可變引數的型別必須後跟 ...,Java 會將所有引數打包成一個數組

Example 程式碼段 3.76:使用 vararg 引數的方法。
public void drawPolygon(Point... points) {
  //…
}

呼叫方法時,程式設計師只需用逗號分隔各個點,而無需顯式建立 Point 物件的 陣列。在方法內部,可以將各個點引用為 points[0]points[1] 等。如果沒有傳遞任何點,則陣列的長度為零。

一個方法既可以有普通引數,也可以有可變引數,但可變引數必須始終是最後一個引數。例如,如果程式設計師需要使用最小數量的引數,則這些引數可以在可變引數之前指定

Example 程式碼段 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 陣列,將返回值分配給陣列,並將陣列返回給呼叫者。但是,如果要將基本資料型別和物件引用混合作為方法的輸出值,這種方法就會產生問題。

有一個更好的方法,定義一個包含所需返回值的特殊返回值物件。在方法內部建立該物件,分配值,並將對該物件的引用返回給呼叫者。這個特殊物件“繫結”到這個方法,只用於返回值,所以不要使用公共類。最好的方法是使用巢狀類,請看下面的示例

Computer code 程式碼清單 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 方法返回一個物件引用,其中包含姓名和年齡的兩個值。請看下面如何使用該物件

Example 程式碼段 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:考慮以下程式碼

Example 問題 3.10:編譯器錯誤。
private int myMethod(int a, int b, String c) {
  if (a > 0) {
    c = "";
    return c;
  }
  int b = b + 2;
  return b;
}

上面的程式碼將返回編譯器錯誤。為什麼?

答案
Example 答案 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 關鍵字建立物件時,它會自動呼叫。建構函式沒有返回值,它的名稱與類名相同。每個類都必須有一個建構函式。如果我們沒有定義建構函式,編譯器會自動建立一個稱為“空建構函式”的預設建構函式。

Computer code 程式碼清單 3.13:自動建立的建構函式。
public class MyClass {
  /**
  * MyClass Empty Constructor
  */
  public MyClass() {
  }
}

靜態方法

[edit | edit source]

靜態方法是一種無需物件例項即可呼叫的方法。它可以直接在類上呼叫。例如,Integer 類的 valueOf(String) 方法就是一個靜態方法

Example 程式碼段 3.79:靜態方法。
Integer i = Integer.valueOf("10");

static 關鍵字使屬性與例項無關。這意味著無法引用單個物件的靜態屬性(因為這種特定物件的屬性不存在)。相反,無論 JVM 中存在一個物件還是一百個物件,靜態屬性只有一個例項。以下是在靜態方法中使用靜態屬性的示例

Example 程式碼段 3.80:靜態屬性。
private static int count = 0;

public static int getNewInteger() {
  return count++;
}

您可以注意到,當您使用 `System.out.println()` 時,`out` 是 `System` 類的一個靜態屬性。靜態屬性與類相關,而不是與任何物件例項相關。這就是 Java 實現一個通用輸出流的方式,我們可以使用它來列印輸出。以下是一個更復雜的用例

Computer code 程式碼清單 3.14:靜態屬性。
public class MyProgram {

    public static int count = 0;

    public static void main (String[] args) {
        MyProgram.count++;

        MyProgram program1 = new MyProgram();
        program1.count++;

        MyProgram program2 = new MyProgram();
        program2.count++;

        new MyProgram().count++;
        System.out.println(MyProgram.count);
    }
}
Standard input or output 程式碼清單 3.14 的輸出
4
測試您的知識

問題 3.11:訪問 Oracle 的 `java.lang.Integer` 類 JavaDoc

這個類有多少個靜態欄位?

答案

4.

  • int MAX_VALUE,
  • int MIN_VALUE,
  • int SIZE
  • Class<Integer> TYPE.
要了解如何過載和覆蓋方法,請參閱 過載方法和建構函式


華夏公益教科書