Определенный общий тип списков в списке - PullRequest
1 голос
/ 08 августа 2011

У меня есть список списков.

Я хотел бы знать, как я могу ограничить универсальные типы каждого из внутренних списков, чтобы каждый элемент внешнего списка содержал внутренний список, который может содержать только один тип объекта.До сих пор я пробовал это:

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

Но есть способы добавить типы объектов во внутренние списки, которые не принадлежат.Есть ли способ указать тип, который принимает внутренний список?

Например, если у меня есть следующие внутренние списки,

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

Как мне создать внешний список, который может содержать всевнутренних списков при сохранении определенного типа, который содержит внутренний список.

Также я не уверен, возможно ли это, или то, что я делаю, - плохой дизайн.Если это плохой дизайн, мы будем очень признательны за лучший дизайн (возможно, есть другая коллекция, которая делает это лучше).

Ответы [ 3 ]

3 голосов
/ 08 августа 2011

Если типы внутренних списков не имеют ничего общего, нет возможности сузить его, и подстановочный знак ? - лучшее, что вы можете сделать.

Если T1 T2и T3 все исходят из базового класса B, тогда вы можете написать:

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

Или аналогичным образом, если они совместно используют интерфейс.Это зависит от того, какие общие функциональные возможности они реализуют, что требует, чтобы они были сохранены в одном и том же списке.

Если вам нужна помощь с дизайном, вам нужно будет объяснить свою ситуацию на примере / примере использования.Возможно, нехорошо хранить их в одной коллекции, если они не имеют ничего общего.

1 голос
/ 09 августа 2011

Это невозможно.Общая информация доступна только во время компиляции.Однако точное содержимое и структура списка списков не будут известны до времени выполнения.Таким образом, компилятор не может дать никаких гарантий относительно того, что будет содержать каждый список.Если вы заранее знаете структуру списка, то было бы лучше рассмотреть класс хранения, например:

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();
    }
}
0 голосов
/ 08 августа 2011

Если у вас есть фиксированное количество типов, которые могут попадать в такие списки, вы можете создать подтип для каждого из этих типов. Это также имеет то преимущество, что вы можете использовать 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<?>>(); 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...