Java Generics: настраиваемые совместимые пустые / непустые списки

#java #generics

#java #дженерики

Вопрос:

У меня есть эта задача создать пользовательскую реализацию универсального списка, которая соответствует следующим требованиям:

  • имеет 3 класса: 1 абстрактный класс (скажем, ExampleAbstractList ), одну реализацию пустого списка (например, ExampleEmptyList ) и один непустой список (например, ExampleNonEmptyList )
  • должна быть возможность добавлять / объединять два неабстрактных класса вместе обоими способами (например, добавлять непустой список в пустой список и наоборот)
  • «разработчики» должны работать с абстрактным классом (например ExampleAbstractList<Integer> list2 = new ExampleNonEmptyList<>(11, list1);
  • ExampleNonEmptyList класс может получить 2 параметра: первый параметр должен иметь некоторый тип, и это будет «заголовок» списка, и второй параметр, который должен быть самим списком ( ExampleNonEmptyList или ExamplenEmptyList )
  • В конечном счете, предоставьте заводскую функцию для изготовления семейств связанных объектов, чтобы скрыть фактическую реализацию

Моя текущая реализация выглядит следующим образом:

 public abstract class ExampleAbstractList<T> {
    protected transient T head;
    protected transient T tail;
    ...
    public abstract void add(T e);
    ...

}

public final class ExampleNonEmptyList<T, U> extends ExampleAbstractList<T> {
    protected ArrayList<T> tail_elements = new ArrayList<>();
    public ExampleNonEmptyList(T head, U tail)
    {
        this.setHead(head);
        this.add((T) tail);
    }

    ...
    @Override
    public void add(T e)
    {
        if(e instanceof ExampleNonEmptyList)
        {
            ExampleNonEmptyList enel = (ExampleNonEmptyList) e;
            T enHead = (T) enel.getHead();
            this.getTailElements().add(enHead);

            for(Object tElem : enel.getTailElements())
            {
                T tailElement = (T) tElem;

                this.getTailElements().add(tailElement);
            }
        } else if (e instanceof ExampleEmptyList) {
            ExampleEmptyList list = (ExampleEmptyList) e;
            if(list.size() == 0)
                return;

            for(Object el : list.getList())
            {
                this.getTailElements().add((T) el);
            }
        } else {
            this.getTailElements().add(e);
        }

        this.updateSize();
    }

    ...
}

public final class ExampleEmptyList<T> extends ExampleAbstractList<T> {

    private final List<T> list = new ArrayList<>();
    ...
    public void add(T e)
    {
        this.getList().add(e);
        this.updateSize();
    }
    ...
}
  

Теперь у меня проблема в том, что я не могу добавить ExampleNonEmptyList к ExampleEmptyList, потому что я получаю следующую ошибку:

incompatible types: ExampleAbstractList <Integer> cannot be converted to Integer (когда я пытаюсь добавить списки целых чисел)

Исключение:

 Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - Erroneous sym type: ExampleAbstractList.add
    at Main.main(Main.java:42)
Java Result: 1
  

Код в Main.java:

 32    ExampleAbstractList<Integer> list0   = new ExampleEmptyList<>(); 
33          list0.add(3);
34          ExampleAbstractList <Integer> list1   = new ExampleNonEmptyList<>(1, list0);
35          ExampleAbstractList <Integer> list2   = new ExampleNonEmptyList<>(32, list1);
36          list2.add(9);
...
Some prints
...          
42         list0.add(list1);
  

Я понимаю ошибку и уверен, что она связана с параметрами типа, но я не могу понять, как это исправить… Кто-нибудь, пожалуйста, может мне помочь?

Спасибо!

Комментарии:

1. Можете ли вы опубликовать полную ошибку?

2. Почему ExampleNonEmptyList имеет два параметра типа вместо одного? В конечном итоге вы все равно приводите только U tail к типу T , и если они будут элементами в одном базовом списке, они должны быть одного типа.

3. @Tenner когда я это делал, я делал это потому, что класс должен получать два аргумента двух разных типов, но теперь я вижу, что могу ссылаться на ExampleAbstractList там вместо ‘U’. Сейчас я это исправил, но это не решает мою проблему.

Ответ №1:

Из вашего кода следует, что вы добавляете один список в другой с помощью list0.add(list1) . Вместо этого попробуйте list0.addAll(list1) метод. метод addAll принимает Collection<? extends E> c в качестве аргумента и должен использоваться в вашем конкретном случае. Больше информации здесь

Комментарии:

1. я сделал это: ‘public void addAll(Collection<? расширяет T> e) { this.getList().addAll(e); this.updateSize(); }’, но я получаю почти ту же ошибку, но теперь она стала ‘несовместимые типы: ExampleAbstractList <Целое число> невозможно преобразовать TCollection<? расширяет Integer>’ вместо просто Integer.

2. Вам просто нужно заменить list0.add(list1) на list0.addAll(list1) . Это то, что вы сделали?

3. да, даже приведено list1 к Collection<?расширяет целое число>

4. ОК. но list0.add(list1) это определенно неверно. Придется копать глубже.