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

2022-07-28 15:01:09

前言

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

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