2013-10-21 162 views
4

假設我有一個類和構造函數TestClass傳遞對象給構造函數傳遞參考

public class TestClass { 
    Foo foo; 

    public TestClass(Foo foo) { 
     this.foo = foo; 
    } 
} 

這裏,構造函數接受一個對象,它是Foo類的一個實例。假設我的static void main(String[] args)執行以下操作,與TestClass完全分開;

  • (1)實例化foo

  • (2)通實例fooTestClass構造

  • (3)變更內部狀態的foo

步驟之後( 3),將foo範圍內的我的TestClass的實例的狀態有變化嗎?

+2

你也可以自己寫一個小程序,雖然我會承認*爲什麼*發生這種事情不一定是你可以通過嘗試小例子來學習的東西。 –

+1

@ DennisMeng這是真的,但是自己做這件事不會泄露經驗豐富的回答者可以覆蓋的任何邊緣情況。 – user2763361

+0

回答您的稱號,Java不具有引用傳遞。它通過價值傳遞參考,而這正在導致您遇到的問題。 –

回答

13

它是不是通過引用。相反,它通過的參考,這是一個微妙但重要的區別。

你在main()方法的其他變異foo後,foo現場還將展示這些突變,因爲你的狀態,因爲這兩個變量指向同一個實例。但是,如果您foo重新分配給了新內容,foo字段將不會更改。如果foo確實通過引用傳遞,則這不會成立。總之,所有東西都是通過Java傳遞的;恰好碰巧通過引用來處理對象,所以這些引用的值被傳遞。

我會試着用一個例子來說明這一點。考慮下面的類:

class A { 
    public int n; 

    public A(int n) { 
     this.n = n; 
    } 
} 

和下面的方法:

public static void mutate(A a) { 
    a.n = 42; 
} 

現在我們可以有這樣的事情:

A a = new A(0); 
A.mutate(a); 

System.out.println(a.n); 
 
42 

我們可以看出,a狀態改爲mutate()。現在讓我們修改靜態方法:

public static void mutate(A a) { 
    a = new A(42); 
} 

,然後再試一次:

A a = new A(0); 
A.mutate(a); 

System.out.println(a.n); 
 
0 

正如你所看到的,a的狀態不變。如果引用已經傳遞給函數,我們會期望重新分配的效果在方法範圍之外是明顯的。儘管如此,一些參考實際上已通過,因爲變異引起的變化也會導致方法外的變化。

+1

+1只是第一段 – MadProgrammer

0

經過步驟(3)後,我的TestClass實例中的foo是否也有 其狀態發生了變化?

是的。

你可能想通過this

更新,以讀...

現在,假設你通過構造一個原始值...

public class TestClass { 
    int foo; 

    public TestClass(int foo) { 
     this.foo = foo; 
    } 

    public String toString() { 
     return "TestClass: " + foo; 
    } 
} 

public static void main(String args[]) { 
    int myFoo = 1; 
    TestClass test = new TestClass(myFoo); 
    myFoo += 2; 
    System.out.println("myFoo = " + myFoo); 
    System.out.println("yourFoo = " + test); 
} 

這將輸出...

myFoo = 3 
yourFoo = 1 

這證明了改變原語值的事實不會改變構造函數/方法維護的值。

同樣的,如果你改變了對象引用之後,你通過它

public class TestClass { 
    Foo foo; 

    public TestClass(Foo foo) { 
     this.foo = foo; 
    } 

    public Foo getFoo() { 
     return foo; 
    } 
} 

public static void main(String args[]) { 
    Foo myFoo = new Foo(); 
    TestClass test = new TestClass(myFoo); 
    myFoo = new Foo(); 
    System.out.println("myFoo == yourFoo = " + myFoo.equals(test.getFoo())); 
} 

將輸出

myFoo == yourFoo = false 

由於對象引用是不一樣的。

+0

值得注意的是,如果你有一個原始類型,而不是一個對象類型(例如,'int'而不是'Foo'),那麼答案就是_no_。 –

+0

@DavidWallace當然不會與此爭論,但這與「如果在將構造函數傳遞給它後創建了一個新的Foo實例,不會在TestClass內改變'Foo'的內部狀態'但是這不是問題,因爲無論如何我讀它......所有這些只是讓我游泳:P – MadProgrammer

+0

當然,不是在那裏爭論,我只是想着OP對邊緣案例的評論,並且想知道「原始人「將被包含在該類別中,如果沒有這個評論,這真的是一個是/否的問題 –

3

enter image description here是的,因爲您將相同的對象分配給Foo類的另一個引用,即對象相同,但由兩個引用引用。

+0

而且隨着討論的進行,場景對於原始類型肯定是不同的:) – Batty