物件引用作為方法引數

本主題解釋了物件引用的概念 ; 它面向那些剛接觸 Java 程式設計的人。你應該已經熟悉了一些術語和含義:類定義,主方法,物件例項,以及在物件上呼叫方法,以及將引數傳遞給方法。

public class Person {

  private String name;

  public void setName(String name) { this.name = name; }

  public String getName() { return name; }

  public static void main(String [] arguments) {
    Person person = new Person();
    person.setName("Bob");

    int i = 5;
    setPersonName(person, i);

    System.out.println(person.getName() + " " + i);
  }

  private static void setPersonName(Person person, int num) {
    person.setName("Linda");
    num = 99;
  }
}

要完全勝任 Java 程式設計,你應該能夠向其他人解釋這個例子。它的概念是理解 Java 如何工作的基礎。

如你所見,我們有一個 main,它將一個物件例項化為變數 person,並呼叫一個方法將該物件中的 name 欄位設定為 Bob。然後它呼叫另一個方法,並將 person 作為兩個引數之一傳遞; 另一個引數是整數變數,設定為 5。

呼叫的方法將傳遞的物件上的 name 值設定為 Linda,並將傳遞給的整數變數設定為 99,然後返回。

那會列印什麼?

Linda 5

那麼為什麼對 person 的更改在 main 中生效,但是對整數的改變不是?

呼叫時,main 方法將 person物件引用傳遞給 setPersonName 方法; setAnotherName 對該物件所做的任何更改都是該物件的一部分,因此當該方法返回時,這些更改仍然是該物件的一部分。

另一種說法相同的方式:person 指向一個物件(儲存在堆上,如果你感興趣的話)。方法對該物件所做的任何更改都是在該物件上進行的,並且不受進行更改的方法是否仍處於活動狀態或已返回的影響。方法返回時,對物件所做的任何更改仍儲存在該物件上。

將此與傳遞的整數進行對比。由於這是一個原始 int(而不是一個 Integer 物件例項),它是按值傳遞的,這意味著它的值被提供給方法,而不是指向傳入的原始整數的指標。該方法可以為方法的更改自己的目的,但這不會影響進行方法呼叫時使用的變數。

在 Java 中,所有原語都是按值傳遞的。物件通過引用傳遞,這意味著指向物件的指標作為引數傳遞給任何接受它們的方法。

這意味著一個不太明顯的事情:被呼叫的方法不可能建立一個物件並將其作為引數之一返回。方法返回由方法呼叫直接或間接建立的物件的唯一方法是作為方法的返回值。讓我們首先看看它是如何工作的,然後是如何工作的。

讓我們在這裡給我們的小例子新增另一種方法:

private static void getAnotherObjectNot(Person person) {
  person = new Person();
  person.setName("George");
}

而且,回到 main,在 setAnotherName 的呼叫之下,讓我們呼叫這個方法和另一個 println 呼叫:

getAnotherObjectNot(person);
System.out.println(person.getName());

現在該程式將列印出來:

Linda 5
Linda

喬治的物體怎麼了?好吧,傳入的引數是指向 Linda 的指標; 當 getAnotherObjectNot 方法建立了一個新物件時,它使用對 George 物件的引用替換了對 Linda 物件的引用。Linda 物件仍然存在(在堆上),main 方法仍然可以訪問它,但是 getAnotherObjectNot 方法之後將無法對它做任何事情,因為它沒有引用它。看起來程式碼的編寫者打算為方法建立一個新物件並將其傳回去,但如果是這樣,它就不起作用了。

如果這是作者想要做的,他將需要從方法返回新建立的物件,如下所示:

private static Person getAnotherObject() {
  Person person = new Person();
  person.setName("Mary");
  return person;
}

然後這樣稱呼它:

Person mary;
mary = getAnotherObject();
System.out.println(mary.getName());

整個程式輸出現在將是:

Linda 5
Linda
Mary

這是整個程式,增加了兩個:

public class Person {
  private String name;

  public void setName(String name) { this.name = name; }
  public String getName() { return name; }

  public static void main(String [] arguments) {
    Person person = new Person();
    person.setName("Bob");

    int i = 5;
    setPersonName(person, i);
    System.out.println(person.getName() + " " + i);
    
    getAnotherObjectNot(person);
    System.out.println(person.getName());
    
    Person person;
    person = getAnotherObject();
    System.out.println(person.getName());
  }
  
  private static void setPersonName(Person person, int num) {
    person.setName("Linda");
    num = 99;
  }
  
  private static void getAnotherObjectNot(Person person) {
    person = new Person();
    person.setMyName("George");
  }
  
  private static person getAnotherObject() {
    Person person = new Person();
    person.setMyName("Mary");
    return person;
  }
}