1

リストのリストがあります。

各内部リストのジェネリック型を制限して、外部リストの各要素に1つのタイプのオブジェクトのみを含めることができる内部リストを含める方法を知りたいです。これまで私はこれを試しました:

List<ArrayList<?>> l = new ArrayList<ArrayList<?>>();

ただし、属していないタイプのオブジェクトを内部リストに追加する方法があります。内部リストが受け入れるタイプを指定する方法はありますか?

たとえば、次の内部リストがある場合、

ArrayList<T1> innerList = new ArrayList<T1>();
ArrayList<T2> innerList2 = new ArrayList<T2>();
ArrayList<T3> innerList3 = new ArrayList<T3>();

内部リストに含まれる特定のタイプを保持しながら、すべての内部リストを含むことができる外部リストを作成するにはどうすればよいですか。

また、これが可能かどうか、または私がしていることが悪いデザインであるかどうかもわかりません。それが悪いデザインである場合、より良いデザインへの洞察(おそらくこれをより良くする別のコレクションがあるかもしれません)は非常にありがたいです。

4

3 に答える 3

3

内部リストのタイプに共通点がない場合、それを絞り込む方法はなく、ワイルドカード?が最善の方法です。

すべてが基底クラスから拡張されている場合はT1 T2、次のように記述できます。T3B

List<List<? extends B>> outerList = new ArrayList<List<? extends B>>();

または、インターフェイスを共有している場合も同様です。同じリストに格納する必要がある、実装している一般的な機能によって異なります。

設計に関する支援が必要な場合は、例/ユース ケースを使用して状況を説明する必要があります。共通点がない場合、それらを同じコレクションに保持するのはおそらく適切な設計ではありません。

于 2011-08-08T19:36:05.653 に答える
1

これは不可能です。一般的な情報は、コンパイル時にのみ使用できます。ただし、リストのリストの正確な内容と構造は実行時までわかりません。したがって、コンパイラは、各リストに何が含まれるかについて保証することはできません。リストの構造を事前に知っている場合は、保持クラスなどを検討することをお勧めします。

class Holder<T,S> {
    List<T> listOfTs;
    List<S> listOfSs;
}

リストがすべて共通のスーパータイプを共有することがわかっている場合は、ワイルドカード境界を使用できます。

List<List<? extends Shape>> list = new ArrayList<List<? extends Shape>>();
list.add(new ArrayList<Circle>());
list.add(new ArrayList<Square>());

これにより、スーパータイプに従ってリストを操作できます。ワイルドカード バウンドの問題は、ワイルドカード バウンド コレクションに要素を追加できないことです。

次の点を考慮してください。

List<? extends Shape> list = new ArrayList<Circle>();
list.add(new Square()); 
// element is a valid shape, but not a valid circle 
// contract of the original list is broken.

特定の数のジェネリックのみを使用することがわかっている場合は、それぞれが表すクラスを格納し、これを使用してリストを型安全な方法でキャストできます。

class ListHolder<T> {
    private final Class<T> clazz;
    private final List<T> list;

    public ListHolder(Class<T> clazz) {
        this.clazz = clazz;
        this.list = new ArrayList<T>();
    }

    public boolean isCircleList() {
        return this.clazz == Circle.class;
    }

    public List<Circle> getCircleList() {
        if (!isCircleList()) {
             throw new IllegalStateException("list does not contain circles");
        }
        return (List<Circle>) list;
    }

    public boolean isRectangleList() {
        return this.clazz == Rectangle.class;
    }

    public List<Rectangle> getRectangleList() {
        if (!isRectangleList()) {
             throw new IllegalStateException("list does not contain rectangles");
        }
        return (List<Rectangle>) list;
    }

    public static void main(String[] args) {
        ListHolder<Rectangle> rectangleListHolder = new ListHolder<Rectangle>(Rectangle.class );

        List<ListHolder<? extends Shape>> list = new ArrayList<ListHolder<? extends Shape>>();

        list.add(rectangleListHolder);

        ListHolder<? extends Shape> shapeWildCardList = list.get(0);

        List<Rectangle> rectangles = shapeWildCardList.getRectangleList();
    }
}
于 2011-08-08T20:08:41.133 に答える
0

そのようなリストに入れることができる固定数のタイプがある場合は、それらのタイプごとにサブタイプを作成できます。これには、 instanceof を使用してリストのタイプを決定できるという利点もあります。これは、異なるタイプのリストのリストがある場合におそらく行う必要があります。

// common supertype for the lists
abstract class SpecialList<T> extends LinkedList<T> {}

// a list for every type:
class T1List extends SpecialList<T1> {}
class T2List extends SpecialList<T2> {}
class T3List extends SpecialList<T3> {}


//use
List<SpecialList<?>> l = new ArrayList<SpecialList<?>>(); 
于 2011-08-08T19:58:47.487 に答える