零基礎學Java(13)方法參數

前言

首先回顧一下在程式設計語言中關於如何將參數傳遞給方法的一些專業術語。按值調用表示方法接收的是調用者提供的值。而按引調用表示方法接收的是調用者提供的變數地址。方法可以修改按引用傳遞的變數的值,而不能修改按值傳遞的變數的值。
 

Java傳參

Java程式設計語言總是採用按值調用。也就是說,方法得到的是所有參數值的一個副本。具體來講,方法不能修改傳遞給它的任何參數變數的內容。
接下來,假定一個方法試圖將一個參數值增加至3倍:

public static void tripleValue(double x) {
    x = 3 * x;
}

然後調用下面這個方法

double percent = 10;
tripleValue(percent);

不過這樣並不能起作用。調用這個方法之後,percent的值還是10。具體的執行過程如下:

  1. x初始化為percent值的一個副本(也就是10)。
  2. x乘以3以後等於30,但是percent仍然是10
  3. 這個方法結束之後,參數變數x不再使用。

然而,有兩種類型的方法參數:

  • 基本數據類型(數字、布爾值)。
  • 對象引用

我們已經知道,一個方法不可能修改基本數據類型的參數,而對象引用作為參數就不同了,可以很容易得利用下面這個方法將一個員工的工資增至三倍:

public static void tripleSalary(Employee x) {
    x.raiseSalary(200);
}

  當調用

harry = new Employee(...);
tripleSalary(harry);

時,具體的執行過程為:

  1. x初始化為harry值的一個副本,這裡就是一個對象引用。
  2. raiseSalary方法應用與這個對象引用。x和harry同時引用的那個Employee對象的工資提高了200%。
  3. 方法結束後,參數變數x不再使用。當然,對象變數harry繼續引用那個工資增至3倍的員工對象。

可以看到,實現一個改變對象參數狀態的方法是完全可以的,實際上也相當常見。理由很簡單,方法得到的是對象引用的副本,原來的對象引用和這個副本都引用同一個對象。

總結
總結一下在Java中對方法參數能做什麼和不能做什麼:

  • 方法不能修改基本數據類型的參數(即數值型和布爾型)
  • 方法可以改變對象參數的狀態
  • 方法不能讓一個對象參數引用一個新的對象

 

實戰例子

public class 方法參數 {
    public static void main(String[] args) {
        /*
         * 測試1:方法不能修改基本數據類型的參數
         * */
        System.out.println("測試tripleValue:");
        double percent = 10;
        System.out.println("之前:percent=" + percent);
        tripleValue(percent);
        System.out.println("之後:percent=" + percent);

        /*
         * 測試2:方法可以改變對象參數的狀態
         * */
        System.out.println("\nTesting tripleSalary");
        Emplpoyee harry = new Emplpoyee("Harry", 50000);
        System.out.println("之前:salary=" + harry.getSalary());
        tripleSalary(harry);
        System.out.println("之後:salary=" + harry.getSalary());

        /*
         * 測試3:方法不能讓一個對象參數引用一個新的對象
         * */
        System.out.println("\nTesting swap:");
        Emplpoyee a = new Emplpoyee("Alice", 70000);
        Emplpoyee b = new Emplpoyee("Bob", 60000);
        System.out.println("之前:a=" + a.getName());
        System.out.println("之前:b=" + b.getName());
        swap(a, b);
        System.out.println("之後:a=" + a.getName());
        System.out.println("之後:b=" + b.getName());
    }

    public static void tripleValue(double x) {
        x = 3 * x;
        System.out.println("方法結束後:x=" + x);
    }
    
    public static void tripleSalary(Emplpoyee x) {
        x.raiseSalary(200);
        System.out.println("方法結束後:salary=" + x.getSalary());
    }
    
    public static void swap(Emplpoyee x, Emplpoyee y) {
        Emplpoyee temp = x;
        x = y;
        y = temp;
        System.out.println("方法結束後:x=" + x.getName());
        System.out.println("方法結束後:y=" + y.getName());
    }
};


class Emplpoyee {
    private String name;
    private double salary;
    
    public Emplpoyee(String n, double s) {
        name = n;
        salary = s;
    }
    
    public String getName() {
        return name;
    }
    
    public double getSalary() {
        return salary;
    }
    
    public void raiseSalary(double byPercent) {
        double raise = salary * byPercent / 100;
        salary += raise;
    }
}

運行結果如下:

測試tripleValue:
之前:percent=10.0
方法結束後:x=30.0
之後:percent=10.0

Testing tripleSalary
之前:salary=50000.0
方法結束後:salary=150000.0
之後:salary=150000.0

Testing swap:
之前:a=Alice
之前:b=Bob
方法結束後:x=Bob
方法結束後:y=Alice
之後:a=Alice
之後:b=Bob
Tags: