19

したがって、私のプログラムには循環型の ArrayList が必要です。

get(int index) メソッドでなければならないのは循環的なことだけです。これはオリジナルです:

    /**
     * Returns the element at the specified position in this list.
     *
     * @param  index index of the element to return
     * @return the element at the specified position in this list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */ 
    public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

index が -1 の場合、インデックス ArrayList.size()-1 の要素を取得する必要があり、index が ArrayList.size() の場合、インデックス 0 の要素を取得する必要があります。

これを実現する最も簡単な方法は、単純に java.util パッケージから ArrayList を拡張し、get(int インデックス) をオーバーライドすることです。これにより、上記の 2 つのインデックスに対して IndexOutOfBoundsException がスローされず、必要なものに変更されます。範囲外の他のインデックスに対して IndexOutOfBoundsException をスローします。

ただし、elementData(index) は

private transient Object[] elementData;

プライベートであるため、クラスには表示されないため、機能させることができません。

また、これには外部ライブラリを使用したくありません。これは、実際のcircularArrayが必要ないため、ニーズに合ったものがないと思うためですが、その機能の一部のみであり、残りの部分は通常のArrayList。

だから私は2つの質問があります:

どうすればこれを機能させることができますか?ArrayList クラス全体を AbstractCollection、Collection、および Iterable と共にプログラムにコピーせずにそれを行う方法はありますか? それは私にとっても悪いデザインのようです。

どうにかしてそれを機能させることができれば、他に注意すべきことはありますか? 上記の変更を行った場合、クラスの動作は希望どおりに変更されますか?それとも、他の望ましくない動作の変更がある可能性がありますか?

編集: 答えてくれてありがとう、これが私がやったことです:

import java.util.ArrayList;

public class CircularArrayList<E> extends ArrayList<E>
{
    private static final long serialVersionUID = 1L;

    public E get(int index)
    {
        if (index == -1)
        {
            index = size()-1;
        }

        else if (index == size())
        {
            index = 0;
        }

        return super.get(index);
    }
}

ArrayList をラップしますが、1 つだけです。他の要素にアクセスしようとすると、最初と最後に通常の ArrayList インデックス以外のものにアクセスしようとすると、例外がスローされるようにします。

4

5 に答える 5

11

あなたが説明したことは、基本的に、必要なインデックスのモジュラスを取得し、リスト内のその要素にアクセスすることです。

継承よりも構成を使用して、次のことができます。

  • interface のラッパー クラスを作成しますList<T>。これを ListWrapper と呼びましょう。
    • List のインスタンスを受け入れるコンストラクターを追加する
    • List インスタンスを保護し、名前を付けますwrapped
  • ラッパー クラスを拡張する

なぜこのすべてがらくたをするのですか?これは実装に依存しません。ある日、この便利さを別の実装で使用したくなるかもしれません。次に、コードを複製する必要があり、地獄が始まります。3 番目の実装も必要な場合に、新しい機能をほんの少しだけ追加すると、あなたは運命づけられます。

間にラッパークラスがある場合:

  • すべてのクラスに List インターフェイスを実装して、独自の機能を持たせることができます
  • ラッパー クラスを 1 か所で変更できます
  • 新しい機能を 1 か所に追加できます。

覚えておいてください、私たちは保守可能でなければならないプログラムを書いています!

ラッパークラス

public abstract class ListWrapper<T> implements List<T> {
    protected final List<T> wrapped;

    public ListWrapper(List<T> wrapped) {
        this.wrapped = wrapped;
    }

    public T get(int index) {
        return wrapped.get(index);
    }

    //omitting the other wrapper methods, for sake of brevity.
    //Note: you still have to add them.
    // Eclipse: Source menu, Generate Delegate methods does the trick nicely
}

今、本当の新しいクラス

public class ModList<T> extends ListWrapper<T> {

    public ModList(List<T> list) {
        super(list);
    }

    @Override
    public T get(int index) {
        int listSize = wrapped.size();
        int indexToGet = index % listSize;

        //this might happen to be negative
        indexToGet = (indexToGet < 0) ? indexToGet+listSize : indexToGet;
        return wrapped.get(indexToGet);
    }

}

注意してください

  • ただし、これはマルチスレッド環境では安全ではありません!
  • 元のリストのすべてのインスタンスに注意してください - それを変更すると、ModList インスタンスも変更されます
于 2013-09-06T14:12:55.233 に答える
2

選択された回答は、インデックスが非常に大きな負の数であり、リストのサイズが小さい場合を処理しません。

サイズ => 10 インデックス => -1000000

これは、すべてのサイズとインデックスを処理する必要がある実装です

import java.util.ArrayList;
import java.util.Collection;

/**
 * A list the loops round to the first element when {@link CircularList#get(int)} is called with an
 * index that is greater than the max index of the list and vice versa.
 *
 * @author Stuart Clark
 */
public class CircularList<E> extends ArrayList<E> {

  public CircularList() {
    super();
  }

  public CircularList(int initialCapacity) {
    super(initialCapacity);
  }

  public CircularList(Collection<? extends E> c) {
    super(c);
  }

  @Override
  public E get(int index) {
    if (isEmpty()) {
      throw new IndexOutOfBoundsException("The list is empty");
    }

    while (index < 0) {
      index = size() + index;
    }

    return super.get(index % size());
  }

}
于 2017-01-26T19:21:43.997 に答える