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并且T3全部从基类扩展B,那么您可以编写:

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 回答