簡體   English   中英

不可變類中的可變對象字段

[英]Mutable object field within an Immutable class

我被分配在Java中創建一個不變的隊列類,在此過程中,我所做的實際上是擁有一個私有的最終arraylist,一個startIndex,一個lastIndex作為字段。 每次執行入隊操作時,都是在arraylist頂部添加新值,並返回具有更改的開始和最后一個索引值的類的新實例。 出隊操作也以類似的方式執行。 這樣,在每個入隊/出隊操作之后,新實例都有其自己的起始索引,數組列表的最后索引值,而前一個實例保留這些字段的舊值。

我的問題是,我可以稱此類為不變的嗎? 謝謝。

不,類不是一成不變的。

基本上,線程和Java內存模型是語言規范的一部分,因此,每當您詢問類的行為時,都必須考慮語言的那些部分。 由於ArrayList並不是線程安全的,並且您對其進行了更改,因此您不能依靠ArrayList表現出預期的行為,例如在存在多個線程的情況下返回其數組中的第一個或最后一個元素。

Java語言規范說:

盡管前幾章中的大多數討論僅涉及一次執行單個語句或表達式(即,通過單個線程)執行的代碼的行為,但是Java虛擬機可以一次支持多個執行線程。 這些線程獨立執行對駐留在共享主內存中的值和對象進行操作的代碼。

線程由Thread類表示。 用戶創建線程的唯一方法是創建此類的對象。 每個線程都與這樣的對象相關聯。 在相應的Thread對象上調用start()方法時,線程將啟動。

線程的行為(尤其是在未正確同步的情況下)可能會造成混淆並且違反直覺。

這是在第17.4.5節中拍攝的金錢

更具體地說,如果兩個動作共享事前發生關系,則它們不一定必須按照順序與沒有事前發生關系的任何代碼發生過關系。 例如,在一個數據競爭中的一個線程中進行寫操作而在另一個線程中進行讀操作可能看起來與這些讀操作的發生順序不一致。

由於ArrayList不是線程安全的(關系之前沒有發生 ),寫入可以任何順序進行-當內部數組初始化為null,某些先前的寫入或最新的寫入時,您可能會看到初始值。 一個人無法分辨。

因此,這是反直觀的,因為您認為如果有一個ArrayList的最后一個元素的索引,則該ArrayList將返回其最后一個元素的值,但是規范說“否”。

閱讀我鏈接到的規范,並獲得Brian Goetz編寫的Java Concurrency in Practice的副本。 那本書基本上是所有線程和Java的聖經。

為了實現不變性,隊列字段的內部狀態決不能由於元素入隊和出隊而改變。 一種方法是創建隊列的全新實例,並每次都支持ArrayList。 與通常的隊列實現相比,這將表現得很差,因為入隊和出隊操作都將花費O(n)時間。

我不確定這有什么用,因為通常假設隊列會更改狀態-但也許您正在尋找這樣的東西:

public class ImmutableQueue<T> {

    private final List<T> elements;

    public ImmutableQueue() {
        elements = new ArrayList<T>();
    }

    private ImmutableQueue(List<T> elements) {
        this.elements = elements;
    }

    public ImmutableQueue<T> enqueue(T element) {
        List<T> copy = new ArrayList<T>(elements);
        copy.add(element);
        return new ImmutableQueue<T>(copy);
    }

    public DequeueResult dequeue() {
        if (elements.size() == 0) {
            throw new NoSuchElementException();
        }
        List<T> copy = new ArrayList<T>(elements);
        T head = copy.remove(0);
        return new DequeueResult(head, new ImmutableQueue<T>(copy));
    }

    public class DequeueResult {

        public final T element;
        public final ImmutableQueue<T> queue;

        public DequeueResult(T element, ImmutableQueue<T> queue) {
            this.element = element;
            this.queue = queue;
        }

    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM