1

私は次のように SpeexRunner クラスを持っています。 のコンストラクターは、ブール変数とLinkedList<short[]>. 次のように :-

public class SpeexRunner implements Runnable {
    public boolean stopThread;
    LinkedList<short[]> dataList;

    public SpeexRunner(boolean val_stopThread, LinkedList<short[]> dataRef){
        this.stopThread = val_stopThread;
        dataList = dataRef;
    }
    @Override
    public void run() {
     //add objects in dataList;
     // change / remove dataList Objects
    }
}

私の質問は:- run() 内の dataList を変更すると、変更は別の場所で宣言されている元のリストに反映されますか?

4

4 に答える 4

5

run() 内の dataList を変更すると、別の場所で宣言されている元のリストに変更が反映されますか?

はい。コンストラクターは、リストのコピーではなく、リストへの参照を受け取ります。コピーする場合は、LinkedList コピー コンストラクターを使用する必要があります。次に、リストの独自のコピーを作成します。ただし、エントリは配列 ( ) であり、配列は参照によって格納されるため、2 つのリストのエントリは引き続き共有されることに注意してください。short[]

これは、おそらく次の例で最もよく示されています。

import java.util.*;

public class ListExample {
    public static final void main(String[] args) {
        List<short[]> list;

        // Direct use (no copies)
        list = new LinkedList<short[]>();
        list.add(new short[] { 0, 0, 0 });
        System.out.println("list.size() before direct use: " + list.size());
        System.out.println("list.get(0)[0] before direct use: " + list.get(0)[0]);
        new DirectUser(list).doSomething();
        System.out.println("list.size() after direct use: " + list.size());
        System.out.println("list.get(0)[0] after direct use: " + list.get(0)[0]);
        // Output, note how both the list and its contents have been changed:
        // list.size() before direct use: 1
        // list.get(0)[0] before direct use: 0
        // list.size() after direct use: 2
        // list.get(0)[0] after direct use: 1

        // Copying the list, but note that the entries are shared by both lists:
        list = new LinkedList<short[]>();
        list.add(new short[] { 0, 0, 0 });
        System.out.println("list.size() before copy-list use: " + list.size());
        System.out.println("list.get(0)[0] before copy-list use: " + list.get(0)[0]);
        new CopyListUser(list).doSomething();
        System.out.println("list.size() after copy-list use: " + list.size());
        System.out.println("list.get(0)[0] after copy-list use: " + list.get(0)[0]);
        // Output, note how our list didn't change (it doesn't have a new entry), but
        // the entry at index 0 *was* changed:
        // list.size() before copy-list use: 1
        // list.get(0)[0] before copy-list use: 0
        // list.size() after copy-list use: 1
        // list.get(0)[0] after copy-list use: 1

        // "Deep" copying, both the list and its entries:
        list = new LinkedList<short[]>();
        list.add(new short[] { 0, 0, 0 });
        System.out.println("list.size() before deep-copy use: " + list.size());
        System.out.println("list.get(0)[0] before deep-copy use: " + list.get(0)[0]);
        new DeepCopyUser(list).doSomething();
        System.out.println("list.size() after deep-copy use: " + list.size());
        System.out.println("list.get(0)[0] after deep-copy use: " + list.get(0)[0]);
        // Output, note that neither the list nor its entries was affected by the call:
        // list.size() before deep-copy use: 1
        // list.get(0)[0] before deep-copy use: 0
        // list.size() after deep-copy use: 1
        // list.get(0)[0] after deep-copy use: 0


        System.exit(0);
    }

    static class DirectUser {
        List<short[]> items;

        DirectUser(List<short[]> items) {
            // DirectUser doesn't copy the list
            this.items = items;
        }

        void doSomething() {
            this.items.get(0)[0] = 1;
            this.items.add(new short[] { 2, 2, 2 });
        }
    }

    static class CopyListUser {
        List<short[]> items;

        CopyListUser(List<short[]> items) {
            // CopyListUser copies the list, but both lists still share items
            this.items = new LinkedList<short[]>(items);
        }

        void doSomething() {
            this.items.get(0)[0] = 1;
            this.items.add(new short[] { 2, 2, 2 });
        }
    }

    static class DeepCopyUser {
        List<short[]> items;

        DeepCopyUser(List<short[]> items) {
            // DeepCopyUser copies the list AND each entry
            this.items = new LinkedList<short[]>();
            for (short[] entry : items) {
                this.items.add(Arrays.copyOf(entry, entry.length));
            }
        }

        void doSomething() {
            this.items.get(0)[0] = 1;
            this.items.add(new short[] { 2, 2, 2 });
        }
    }
}

リストを使用するDirectUserと、呼び出しコードで、リスト (リストが長くなったという点で) とその内容 (最初のエントリの最初のスロットが から0に変更された1) の両方に変更が見られました。

それCopyListUserを使用すると、リストのコピーが作成されたので、呼び出しコードでリストに変更は見られませんでした (長くなりませんでした)。しかし、最初のエントリに変更0見られました (両方のリストが同じ配列オブジェクトを共有していたため) — 最初のスロットが からに1再び変更されました。

それDeepCopyUserを使用するとリストのコピーと各エントリのコピーが作成されるため、物事は完全に完全に切断されました。リストまたはその項目への変更は、呼び出しコードによって確認されませんでした。

于 2012-04-17T11:16:44.773 に答える
3

run() 内の dataList を変更すると、別の場所で宣言されている元のリストに変更が反映されますか?

簡単な答え: はい。

少し長い回答: はい。Java ではパラメーターは常に参照によって渡されるためです。

(変更を禁止または無視する(仮想の)サブクラスを使用する可能性がありますLinkedList。その場合、試行された変更は例外になるか、効果がありません。ただし、それはひねくれたものになります...)

于 2012-04-17T11:16:53.853 に答える
2

はい、スレッドがリストのコピーではなく、リストへの参照を持っているためです。同期されていないLinkedListことに注意してください:

複数のスレッドがリンクされたリストに同時にアクセスし、少なくとも 1 つのスレッドがリストを構造的に変更する場合は、外部で同期する必要があります。

于 2012-04-17T11:16:51.943 に答える
2

リストに要素を追加したり、リストから要素を削除したりすると、コードの残りの部分から変更が表示されます。複数のスレッドを使用する場合は、同期を使用して、変更が表示されることを保証する必要があることに注意してください。

一方、変更をクラスから逃れたくない場合は、コンストラクターで新しい List を作成し、元のリストにすべての項目を追加できます。その場合、リストへの変更は外部からは見えませんが、リスト内の項目を変更すると、それらの変更が表示されます。

于 2012-04-17T11:17:02.557 に答える