2011-04-13 37 views
3

請給我舉例,我可以看到不可變對象的優點。我在網上找到的信息集中在線程中。我還不知道線程。如果這些例子會使用簡單的原則,那將是非常好的java:示例中不可變對象的優點

+0

Java的主要優勢在於使用線程。除非你對線程有基本的瞭解,否則你可能沒有意義。當你有編程經驗和可能出錯的事情時,它更有意義。特別是大型複雜項目。 – 2011-04-13 16:46:05

+0

如果您知道對象的狀態不能從外部進行更改,它可以簡化您對代碼中交互的理解。 – birryree 2011-04-13 16:48:18

回答

3

這不是一個可以用例子有用地解釋的概念。不可變對象的優點是你知道他們的數據不能改變,所以你不必擔心這一點。你可以自由地傳遞它們,而不必記住你傳遞給它們的方法是否可以用你的代碼不準備處理的方式來改變它們。這使得使用不可變數據更容易。

對於多線程來說,這個優勢更重要,因爲基於多線程的數據以不應該被改變的方式改變數據通常是不可重複的 - 它們依賴於時序,因此有時會發生,有時不會發生,這使得它們很難分析和修復。

1

當對象通常共享時,不可變對象非常有用 - 不僅僅與線程共享,而且還用於單線程程序以及對象有許多客戶端的情況。

例如,String可能是Java中最常用的不可變對象。阻止該字符串的用戶更改其內容是不可改變的。如果String是可變的,則意味着每個用戶都必須創建該字符串的唯一副本,以確保沒有其他人正在更改它。

不可變的數據也有安全隱患。例如,與用戶關聯的安全令牌應該是不可變的,否則流氓程序可以輕鬆更改與該令牌關聯的用戶。

0

這裏的主要思想是通過使用不可變對象來使你的類的線程安全。我認爲這article是一個很好的閱讀。

希望這會有所幫助!

0

一個很好的例子是String類:

的原因不可變對象一個很好的總結,可以發現here

1

正如你已經知道,它是一個多線程的大格局。

這也意味着很多更好的封裝。你可以傳遞這些對象並共享它們,而且你永遠不必擔心有人會改變你的對象的狀態。

Java核心庫中有一些很棒的例子。數量子類是一個,但我認爲最好的例子是String。你傳遞它們,連接,獲取子串等,而不需要考慮其他地方。如果它像C/C++ char[]一樣可變,那麼您總是需要牢記這一點。

出於同樣的原因,它也導致更具可讀性和可維護性代碼。不需要關心對象的其他用戶。

這兩個原因導致我們另一個重要模式值對象。簡言之,這是有道理的,當你關心一些特定值(日期,數字,字符串,區間,金錢,或者如果你需要一些稍微複雜的對象),但價值本身沒有身份即,無論上下文如何,它都具有完全相同的含義。

1

從Java返回的值(即對象引用從方法返回),例如,如果我返回一個字符串,像這樣:

private String myString = "foo"; 

public String getString() { 
    return this.myString; 
} 

和String類是不是一成不變的,那麼的getString()呼叫者可能會修改myString,這可能不是所需的行爲;系統的其他部分可能不希望或期望myString更改。因此,主叫方可以其myString點對象只改變,不myString本身。

+0

'按價值'是一個參考?我以爲他們是彼此相反的? – Dennis 2012-09-27 19:52:45

+0

你必須記住,在上面的例子中,myString實際上是對String對象的引用,而不是對象本身。所以返回this.myString通過值返回對myString的引用。 – Dunnie 2013-11-06 17:12:21

+0

根據我的信息,Java字符串是不可變的,所以我不認爲調用者可以修改原始私有對象myString。當他嘗試修改它時,會創建一個新的String obj。 – 2015-02-02 07:06:59

1

這是一種重複術語,但不可變對象的主要優點是它們不能更改。當對象可以改變時,你必須考慮可能發生的事情。你必須考慮如何,何時以及爲什麼要改變它們。你必須考慮應用程序中的其他代碼可能訪問同一個對象,以及它可能會在不知情的情況下進行更改。不可變的對象有效地減少了「移動部件」的數量(和粒度),您必須在系統中進行操作並讓您的生活更輕鬆。

9

不變性是多線程程序很重要,因爲你知道,一個線程會在另一個線程沒有損壞的值使用。但它在單線程程序中也很有用。

這裏有一個簡單的例子:

Integer i=Integer.valueOf(17); 
foo(i); 
bar(i); 

你可能會想知道,什麼樣的價值傳遞給吧()?

假設foo()從一個大的,複雜的功能。在這個例子中,我知道絕對的事實,當foo完成時,我仍然等於17,因爲整數是不變的。如果不是這樣,我就得研究foo來判斷它是否會改變。

下面是一個稍微複雜一點的例子。假設我有一個類似Integer的對象,但是可以修改。我們稱之爲MutableInteger。然後說我寫這個:

MutableInteger currentInventory=findQtyInInventory(); 
MutableInteger neededInventory=currentInventory; // copy current for starters 
... bunch of other code ... 
neededInventory.subtract(allocatedToSales); 
currentInventory.add(arriving); 
... bunch of more code ... 
if (neededInvenory.compareTo(currentInventory)>0) 
    display("Shortage!"); 

你是否看到上述問題? neededInventory和currentInventory指向同一個對象。所有的加減操作都是在相同的值上執行,而不是兩個不同的值,所以當我們進行測試時,它總是相等的。如果對象是可變的,上面的代碼將不會工作。如果它們是不可變的,那麼增加和減少將不得不返回一個結果對象,而不是在原地進行更新,而且這將起作用。

幾年前,我使用Fortran編譯把整數WERE可變的。我們有一個接受幾個參數的函數,其中一個是整數。在一些極少數情況下,函數更新了整數。然後有一天有人給這個函數寫了一個調用,傳遞常量「2」作爲整數。該函數決定更新參數,從而將「常量」2更改爲1!現在使用常量2的程序中的其他每個地方都神奇地獲得了值1。這花了很長時間來調試。

+0

哇,我以爲我是唯一一個能夠記住那個回Fortran的人。 – 2011-07-01 21:15:40

+1

因此,如果聲明Java必須始終通過引用而不是複製,那麼這將更清晰。所以所有傳遞的值都可以被修改,除非它們是不可變的。然而,我認爲它是PHP,它像Java那樣通過有價值的方式來保存複製時間和內存,但如果對象被修改,那麼它會被複制,然後函數/方法不會修改對象。 – Dennis 2012-09-06 01:47:23

+0

@丹尼斯嗯,有時候你想要修改一個傳入的對象。例如,使用訂購商品列表創建訂單對象,然後將其傳遞給計算銷售稅並將其填充到訂單對象的函數。它不是非常不可變的=好的/可變的=不好的,因爲知道你在做什麼。對於需要您說出您是通過引用還是通過價值傳遞的語言,因此允許並要求您明確決定的語言有些東西需要說明。 – Jay 2012-09-06 17:36:39