2011-12-02 18 views
0

如果Java總是通過引用傳遞變量,爲什麼日食生成任何考慮豆。日食 - 如何來生成getter和setter不考慮「通過引用」

代替: return myStr;

必須 return new String(myStr);

沒有?

編輯
好吧,我的例子很糟糕。
讓我們離開日食,當我想返回一個自定義對象。我是否需要創建一個「複製構造函數」並將其返回,如下所示:

return new MyCustomObject(myCustomObject); 


class MyCustomObject{ 

    private String str; 
    public MyCustomObject(String str){ 
    this.str = str; 
    } 

    public MyCustomObject(MyCustomObject obj){ 
    this.str = obj.str;  
    } 
} 

我必須寫那個嗎?

+3

'字符串'是不可變的;沒有意義返回一個新的。 – alf

+0

Java總是按價值傳遞。對象引用也是按值傳遞的。 –

回答

5

在Java中,每個對象變量都是引用。對象不能被值傳遞,只有原語可以(並且總是)。那麼,這有點誤導。該參考是按值傳遞,但你能想到的一切作爲參考,只要不是在C++的觀點。

也許是最容易使用的例子。

SomeObject foo; 

public void doSomething(SomeObject bar) { 
    bar.whatever(); 
    bar = new SomeObject(); 
    bar.someOtherMethod(); 
} 

public void doStuff() { 
    foo = new SomeObject(); 
    doSomething(foo); 
} 

所以,foo是的SomeObject實例的引用。當doSomething被調用時,該參考值被複制到bar,所以現在foobar是相同的SomeObject引用。

bar.whatever()foo所指的同一對象調用whatever

bar = new SomeObject()意味着foobar現在參閱不同SomeObject實例,所以someOtherMethod稱爲該foo是指在對象上。

這是C++完全不同的,其中

void doSomething(SomeObject& bar) { 
    bar = whatever; 
} 

具有完全不同的含義。你真的不應該用C++來考慮Java。

關於您的示例,String s在Java中是不可變的,所以即使對象可能按值傳遞也沒關係。

關於你的第二個例子,如果你想返回一個對象,調用者不能用污染的內部狀態,那麼,是的,你需要有一個拷貝構造函數(或等價的東西)。

例如:

class ClassWithInternalList { 
    private List<String> reallyImportantData; 

    public List<String> getImmutableViewOfData() { 
     // Take advantage of the java.util.Collections tool for making a List immutable. 
     return Collections.unmodifiableList(reallyImportantData); 
    } 

    public List<String> getSafeCopyOfData() { 
     // Return a copy that the caller can modify without changing reallyImportantData. 
     return new ArrayList<String>(reallyImportantData); 
    } 

    public List<String> justGetTheData() { 
     // Return a reference to reallyImportantData that the caller can modify at will. 
     return reallyImportantData; 
    } 
} 

可以選擇根據情況適當類型的返回值(正常參考,不可變的視圖或複製)。根據你正在做的事情,三種選擇中的任何一種或全部都是合適的。

java.util.Collections可以很容易地獲得Collection的不可變視圖,但對於自定義類您需要做自己的不變性。

請記住,如果存在可變性問題,則只需執行此操作。您的MyCustomObject示例仍然是不可變的(因爲調用者無法更改返回的MyCustomObject實例中的任何狀態),所以問題仍然有點不切實際。

0

如果變量是原始的或不可變的,那麼您修改返回的內容不會影響原始屬性。

其他條件,變量是一個自定義類型,也許你的類定義了一個像String一樣的構造函數,也許不是。所以日食不知道如何生成它的副本。

衆所周知,java傳遞引用,所以java程序員用於返回引用並允許其他modify.Eclipse實現它作爲默認值。

如果你不喜歡它,你可以返回一個副本或實現Immutable。

+0

請解釋'..或實現Immutable'謝謝 – SexyMF

+0

如果一個對象在構造後狀態無法更改,則該對象被認爲是不可變的。最大程度地依賴不可變對象被廣泛接受爲創建簡單可靠代碼的合理策略。不可變對象在併發應用程序中特別有用。由於它們不能改變狀態,所以它們不能被線程干擾破壞或在不一致的狀態下觀察到。 – xie

+0

BigDecimal是一個實例 – xie

-1

您通常不希望在使用getter時創建新對象。你通常想要的是讓對象屬性的引用更容易處理,封裝並且在使用屬性值之前改變屬性的值時也能得到正確的值。

通過經常調用的方法創建對象的新實例,並不期望這樣做,甚至不會聲明做這樣的事情正在驚嚇反模式

+1

它根本不是一種反模式,通常需要精確地保持封裝並確保一個對象是不可變的。例如,String.getChars(...)總是返回一個新的char數組,這是一件好事。製作日期(這是可變的)的防禦副本通常是一個好主意。將列表包裝成不可修改的列表通常是一個非常好的主意。 –

+0

顯然你沒有仔細閱讀我的答案。例如,String.getChars()不會創建目標數組,它是其中一個參數,文檔中明確指出某些內容被複制。使用不可變類型或包裝是完全不同的故事。 –

+0

那麼,複製構造函數主要用於保持不變性,OP會詢問他是否應該使用它們,所以我不會說這是一個完全不同的故事。順便說一句,除了你的答案,所有的答案都是關於不變性的。 –