2014-11-01 56 views
1

是否需要使不可變類private的字段好像它們被標記爲final一樣,不能更改?
我的意思是僅僅將這些字段標記爲final就足夠了嗎?java中的不可變類

(我知道這是沒有必要的不可變類有最終的領域,但它最好有它的類編譯時檢查內部。)

+0

成員字段可能有它們自己的mutator方法,所以你不希望這些方法被公開。 – 2014-11-01 10:27:50

回答

1

讓私有變量通過getter訪問給你更多的自由與類的實現。例如,您可以用一個計算或檢索訪問值或緩存結果的實現來替換一個簡單的getter。

將字段保持爲私有狀態的另一個原因是即使當字段是可變對象時也是如此。在這種情況下,對象可以改變,即使它是最終的,通常不是你想要的。這是一個大概是不可變的類的例子,它帶有一個可變的Date類的公共final字段。

class DateHolder { 
     public final Date date; 
     DateHolder(Date date) { 
      this.date = date: 
     } 
} 

// ... 

DateHolder holder = new DateHolder(Date.now()); 

// this doesn't work because date is final: 
//holder.date = new Date(2013, 11, 23); 

// but this works even though date is final: 
holder.date.setYear(2013); 
+0

我明白了。結合這個答案和鮑里斯蜘蛛的答案使我對它更加清楚。保持字段私有和getters返回不可變。謝謝 ! – iAmLearning 2014-11-01 11:05:01

1

final場只能從構造方法中分配給。因此,製作字段final足以使它們在建造後不可變。分配指向可變對象的指針是另一回事。

+1

這個不同的故事會是更有趣的一個。 – Philipp 2014-11-01 10:36:45

+0

'final'字段也可以在聲明時初始化。我也同意Philipp的觀點。拋開「有趣」的部分,這是一個無法回答的問題。 – 2014-11-01 10:37:11

7

沒有這是不夠的。

考慮這個例子:

final class ImmutableClass { 
    private final List<String> data; 

    public ImmutableClass(final List<String> data) { 
     this.data = data; 
    } 

    public List<String> getData() { 
     return data; 
    } 
} 

這個類是final所以不能延長。這是data字段是final因此在分配後不能更改。

final ImmutableClass immutableClass = new ImmutableClass(data); 
immutableClass.getData().add("Some other value"); 

哎呀。

因此,爲了使一類真正不變的各個領域也應該是一成不變的類,或有防守副本

例如,糾正問題,你需要做的是:

final class ImmutableClass { 
    private final List<String> data; 

    public ImmutableClass(final List<String> data) { 
     this.data = new ArrayList<>(data); 
    } 

    public List<String> getData() { 
     return Collections.unmodifiableList(data); 
    } 
} 

而這只是因爲作品String是不可改變的。如果您有,例如,List<Date>您還需要複製個人Date對象。

+0

感謝您寶貴的答覆。 – iAmLearning 2014-11-01 11:08:05

+0

我想用refelction API可以在運行時更改數據字段的內容嗎? – 2015-01-07 17:32:38

+0

@KickButtowski用反射可以將'Boolean.TRUE'的值更改爲'false'。防止反射的唯一方法是使用「SecurityManager」。因此,在大多數情況下,反射的影響被忽略。 – 2015-01-07 17:34:38