web-dev-qa-db-ja.com

円形ArrayList(拡張ArrayList)

したがって、私のプログラムには、循環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);
    }

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

これを実現する最も簡単な方法は、Java.utilパッケージからArrayListを拡張し、get(int index)をオーバーライドするだけなので、上記の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インデックス以外の要素を使用して、最初と最後以外の要素にアクセスしようとすると、例外をスローします。

16
Karlovsky120

ArrayListから派生して、これらの行に沿ってget(int index)メソッドをオーバーライドすることはできません。

@Override
public E get(int index)
{
    if(index < 0)
        index = index + size();

    return super.get(index);
}

私は何が欠けていますか?

この実装では、任意のインデックスを有効なインデックス範囲に折り畳むことはできませんが、左側と右側の両方からリストを適切にアドレス指定することができます(それぞれ正と負のインデックス、Pythonのように)。

9
HerrB

getフィールドにアクセスする必要なく、ArrayListクラスを拡張してelementDataメソッドの機能を変更できます。

_public class CircularList<E> extends ArrayList<E> {

    @Override
    public E get(int index) {
        return super.get(index % size());
    }
}
_

_super.get_メソッドは引き続き範囲チェックを実行します(ただし、それらは失敗しません)。

これを行うと、ArrayListのインデックスが不安定になる可能性があることに注意してください。リストのサイズが変更されると、通常の範囲外のすべてのインデックスが変更されます。たとえば、リスト_['a','b','c','d','e']_がある場合、get(7)cを返します。 add('f')を実行すると、bは5を法としてではなく6を法として動作するため、get(7)は突然getを返します。

27
Ghostkeeper

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

継承を介した構成で次のことができます。

  • インターフェイス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インスタンスも変更されます
11
ppeterka

選択された答えは、インデックスが非常に大きな負の数であり、リストのサイズが小さい場合、つまり、.

サイズ=> 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());
  }

}
2
Stuart Clark

誰でもこのAbstractList拡張機能を知っていますか:com.Sun.appserv.management.util.misc.CircularList<T>。それを見てください。 GlassFish Java.netコミュニティソリューションです。 GlassFish Container内のスレッドスケジューリングで使用されるため、強力なはずです。

0
red1kissi