2012-05-10 90 views
16

如果將對象引用傳遞給某個方法,是否可以將該對象設置爲只讀方法?是否可以將某個對象設置爲只讀方法

+5

有一箇舊的,但仍然很好的資源:http://www.cs.uwm.edu/~boyland/papers/readonly-talk.pdf –

+0

如何存儲對象的引用,克隆它並且如果沒有改變,不時比較一下? –

回答

15

不嚴格地說。也就是說,可以改變對象的引用不能變成不能改變對象的引用。此外,除了使用約定之外,沒有辦法表示類型是不可變的或可變的。

確保某種形式的不變性的唯一功能是final領域 - 寫一次,他們不能被修改。

也就是說,有設計類的方法可以防止不需要的突變。這裏有一些技巧:

  • Defensive Copying。傳遞一個對象的副本,這樣如果它發生了變異,它不會破壞你的內部不變量。

  • 使用訪問修飾符和/或接口僅暴露只讀方法。您可以使用訪問修改(public/private/protected),可能與接口相結合,以便只有某些方法對其他對象可見。如果暴露的方法本質上是隻讀的,那麼您是安全的。

  • 使您的對象默認爲不可變。對象的任何操作實際上都返回對象的副本。

另外,還要注意的是,在SDK API都有有時返回一個對象的不變版本的方法,例如Collections.unmodifiableList。試圖改變一個不可變列表會引發異常。這不會在靜態(在靜態類型系統的編譯期)強制執行不變性,但是它是動態(在運行時)動態強制執行的廉價而有效的方法。

有很多關於Java擴展的研究建議,以更好地控制混疊和可訪問性。例如,添加一個readonly關鍵字。據我所知,它們中沒有一個計劃包含在未來版本的Java中。你可以看看這些指針如果你有興趣:

Checker框架非常有趣。在Checker框架中,查看通用Universe類型檢查器,IGJ不變性檢查器和Javari不變性檢查器。該框架使用註釋工作,所以它不是侵入性的。

+0

只讀pdf遭受鏈接腐爛。 – flup

3

不可以,但你可以嘗試傳遞之前,克隆的對象,所以該方法所做的任何更改都不會影響原來的對象。

6

不,不是沒有裝飾,合成,克隆等

6

有這個問題並沒有一般機制。您需要編寫特殊代碼來實現它,比如編寫一個不可變的包裝器(請參閱Collections.unmodifiableList)。

1

您可以定義對象的所有參數final但使只讀到每個人的對象。

3

你可以通過克隆Object的方法,像這樣的第一條語句實現在大多數情況下,類似的事情......

public void readOnlyMethod(Object test){ 
    test = test.clone(); 
    // other code here 
} 

所以,如果你叫readOnlyMethod(),並通過在任何Object,一將採取Object的克隆。該克隆使用與該方法的參數相同的名稱,因此沒有意外更改原始Object的風險。

+1

這需要對象真正地實現'clone',因爲這是一個可編輯的API,所以現代的類很少會受到它的困擾。 –

+0

正確。不過,我希望大多數核心Java類應該正確實現'clone()',所以這將覆蓋大多數情況。它可能與您將獲得只讀參數一樣近。 – wattostudios

+1

'Collections.unmodifiableList'如何來自核心API(不克隆)。 –

0

取決於您希望執行規則的位置。如果您正在協作處理項目,請使用final並附帶評論,告訴下一個人他們不打算修改此值。否則,你會不會只是寫方法而不是觸摸對象?

public static void main(String[] args) { 
    cantTouchThis("Cant touch this"); 
} 

/** 
* 
* @param value - break it down 
*/ 
public static void cantTouchThis(final String value) { 
    System.out.println("Value: " + value); 
    value = "Nah nah nah nah"; //Compile time error 
} 

所以專門來此方法,值將不會被寫入,它是在編譯時強制使該解決方案非常強大。在此方法的範圍之外,對象保持不變,而不必創建任何類型的包裝器。

0
private boolean isExecuteWriteQueue = false; 
public boolean isWriting(){ 
    final boolean b = isExecuteWriteQueue; 
    return b; 
} 
1

使其實現一個接口,它只有只讀方法(沒有setter方法),這給出了一個對象的副本(道路只複製),並返回接口的只讀實例,而不是返回實例一個對象本身

相關問題