我有一份清单清单。
我想知道如何限制每个内部列表的泛型类型,因此外部列表的每个元素都包含一个内部列表,该列表只能包含一种类型的对象。到目前为止,我已经尝试过这个:
List<ArrayList<?>> l = new ArrayList<ArrayList<?>>();
但是有一些方法可以将对象类型添加到不属于的内部列表中。有没有办法指定内部列表接受的类型?
例如,如果我有以下内部列表,
ArrayList<T1> innerList = new ArrayList<T1>();
ArrayList<T2> innerList2 = new ArrayList<T2>();
ArrayList<T3> innerList3 = new ArrayList<T3>();
如何创建一个可以包含所有内部列表的外部列表,同时保留内部列表包含的特定类型。
此外,我不确定这是否可行,或者我正在做的是糟糕的设计。如果它是糟糕的设计,那么对更好的设计的洞察力(也许有一个不同的集合可以做得更好)将非常感激。
答案 0 :(得分:3)
如果内部列表的类型没有任何共同之处,则无法将其缩小,并且通配符?
是您可以做的最佳。
如果T1
T2
和T3
都来自基类B
,那么您可以写:
List<List<? extends B>> outerList = new ArrayList<List<? extends B>>();
或者如果他们共享一个界面。这取决于他们实现的常见功能,要求将它们存储在同一个列表中。
如果您需要设计方面的帮助,您需要通过示例/用例解释您的情况。如果它们没有任何共同点,那么将它们保存在同一个集合中可能不是一个好的设计。
答案 1 :(得分: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();
}
}
答案 2 :(得分: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<?>>();