[英]Different between immutable and effectively immutable objects?
這是Java Concurrency in Practice中的一句話
共享只讀對象包括不可變和有效不可變對象。
不可變和有效不可變對象之間有什么區別?
不可擴展且其字段都是final
且本身不可變的類的實例是不可變的。
由於其方法的細節而無法變異的類的實例實際上是不可變的。 例如:
final class C {
final boolean canChange;
private int x;
C(boolean canChange) { this.canChange = canChange; }
public void setX(int newX) {
if (canChange) {
this.x = newX;
} else {
throw new IllegalStateException();
}
}
}
C
某些實例實際上是不可變的,有些則不是。
另一個例子是零長度數組。 它們實際上是不可變的,即使它們的包含類不可證明是不可變的,因為它們中沒有可以改變的元素。
Joe-E使用驗證程序來證明某些類僅允許不可變實例。 任何標有Immutable
標記接口的東西都會被檢查,並且像String
這樣的String
(因為它的char[]
不會逃脫而實際上是不可變的)會被視為不可變的。
由Joe-E庫定義的Immutable接口由語言專門處理:Joe-E veri fi er檢查實現此接口的每個對象是否(深度)不可變,如果不能自動生成,則會引發編譯時錯誤VERI網絡版。
這是我從谷歌搜索和發現這篇文章的理解。 一個有效不可變的對象是一個包含可以變異的字段的對象,但它不會讓任何東西改變這些字段,因為它永遠不會給你一個引用。 例如,假設您創建了一個包含ArrayList
的類。 ArrayList
是可變的,但是如果你的類總是返回ArrayList的副本,並且你的類中的其他所有東西都是不可變的,那么你的類已經變得有效不可變:沒有辦法改變你的類的實例的狀態。
博客文章將此作為有效不可變類的示例:
import java.awt.*;
public class Line {
private final Point start;
private final Point end;
public Line(final Point start, final Point end) {
this.start = new Point(start);
this.end = new Point(end);
}
public void draw() {
//...
}
public Point getStart() {
return new Point(start);
}
public Point getEnd() {
return new Point(end);
}
}
Point
對象是可變的,但沒關系,因為這個類沒有給任何人直接引用它的 Point實例。 相反,它返回一個具有相同值的新實例。 這樣,沒有人可以改變Line
類的狀態。 這使得Line
類有效地不可變。
那么這與一個真正不可改變的階級有什么不同呢? 一個真正不可變的類具有也是不可變的字段。 讓我們想象Line
是真正不可改變的。 要做到這一點,我們還必須想象Point
是不可變的。 做出這些假設, getStart()
方法可以像這樣編寫:
public Point getStart() {
return start;
}
看看這個答案:
有效不可變和不可變有效不可變和不可變之間的區別在於,在第一種情況下,您仍然需要以安全的方式發布對象。 對於不需要的真正不可變對象。 所以真正的不可變對象是首選,因為它們更容易發布,我上面說的原因說明為什么你可能更喜歡不同步的發布。
不可變對象完全封裝了它們的內部狀態,並且它們不允許在構造之后修改該狀態(可能使用final等),因此它們在多個線程之間共享是安全的,因為從共享對象讀取對多個線程無害。
有效的不可變對象可以在多個線程之間共享之前改變它們的狀態,但是在它們被“發布”之后(即多個引用被賦予多個線程)它們保護自己不被修改。
不可變對象阻止您使用有用的軟件工程實踐,如延遲初始化,因為為了延遲屬性或字段,它們必須是可變的,違反了它們的無憂無慮的並發共享屬性。 有效的不可變對象通過仔細地知道何時可以安全地修改其內部狀態以及何時被禁止來放松這些約束以獲得兩種世界方法的最佳效果。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.