2012-03-21 49 views
1

我知道,在java中傳遞對象時,對象的引用作爲值傳遞。所以你對這個對象所做的任何改變都反映在原始對象中。爲了避免這種情況,我們在java中使用了不變性屬性。java中的不變性屬性

所以我的問題是,我已經創建了一個不變Employee,當我通過這個Employee類在其他類中的一些方法的對象,我不希望這樣的方法來對這個對象的任何變化。即使如此,我也不希望這些更改受到調用類中創建的原始對象的影響。

這是我的示例代碼。

public final class Employee { 
    int employeeId; 

    public int getId() { 
     return employeeId; 
    } 

    public void setId(int id) { 
     this.employeeId = id; 
    } 

} 

public class Worker { 
    public static void process(Employee f, Employee g){ 
     int c = f.getId(); 
     f.setId(g.getId()); 
     g.setId(c); 
    } 
} 

public class ImmutabilityTest{ 

    public static void main(String[] args) { 
     Employee teamMember = new Employee(); 
     Employee teamLead = new Employee(); 
     teamMember.setId(5); 
     teamLead.setId(10); 
     System.out.println("Before process "+teamMember.getId() + " " + teamLead.getId()); 
     Worker.process(teamMember, teamLead); 
     System.out.println("After process "+teamMember.getId() + " " + teamLead.getId()); 
    } 
} 

輸出將是

Before process 5 10 
After process 10 5 

有什麼辦法,以避免在Employee類的成員變量的值的變化? (除了讓他們final)如果不是那麼我們如何實際利用不變性在用戶定義的類中的Java屬性?

任何建議/意見/指針表示讚賞!謝謝..

回答

5

不變性不是Java中的屬性,該屬性可以被應用到對象與單個關鍵字,其一個需要在個案基礎上實施的戰略。一般而言,您使用final關鍵字和克隆爲了完成此。請注意,物體嵌套越深,達到真實物體不變性的難度越高。

這是你的Employee類的(更)不可改變的版本:

public class Employee { 
    final int employeeId; 

    public Employee(final int id) { 
     super(); 
     this.employeeId = id; 
    } 

    public int getId() { 
     return employeeId; 
    } 
} 

注意,在Java中反射使得它幾乎不可能實現真正的不變性,即使使用的最終實例變量和克隆。

+0

感謝您的洞察.. – Rakesh 2012-03-21 06:16:59

4

Employee有一個setter 有一個非私人領域,因此它是不immutable

刪除setter,並使字段private,您的問題得到解決。

你的另一種選擇是通過所述對象的拷貝(通常使用copy constructor創建它)

+0

即使我刪除了setter,它沒有任何區別。我仍然可以改變值'teamMember.id = 15' – Rakesh 2012-03-21 06:10:30

+0

@Rakesh好點 - 我編輯答案 – Bohemian 2012-03-21 06:12:42

+0

感謝您的建議.. – Rakesh 2012-03-21 06:26:59

1

您可以將setId方法的可見性更改爲封裝私有方式,並確保WorkerEmployee的封裝格式不同。

或者完全刪除setId方法。

[如果其他類進行更改]我不希望更改受到在調用類中創建的原始對象的影響。

如果你想要採取這種做法,那麼你需要創建和傳遞原始對象的副本


需要注意的是,除非你聲明的私人employeeId場是final,你不會得到永恆的全部好處。嚴格地說,如果有可能不同的線程在同一Employee實例上調用getId,則需要同步getId方法。

+0

感謝您的答案 – Rakesh 2012-03-21 06:25:43

0

如果你不想讓別人改變你的屬性值,你可以把它們保持爲私人的,而不需要setter。

1

final關鍵字應用於類只是表示該類不能擴展(或分類)。

它與它的成員是否可以修改無關。

+0

+1:感謝您的更正,我混淆了最後和不可變的字符串類! :-) – Rakesh 2012-03-21 06:24:13