Невозможно создать экземпляр универсального элемента в списке Java

У меня есть общий класс, похожий на этот

public class NetworkItems<T> {

    private Status status;
    private T items;

    public NetworkItems() {
        this.status = Status.FAILURE;
        this.items = null;
    }

    public NetworkItems(Status status, T listItems) {
        this.status = status;
        this.items = listItems;
    }

    public NetworkItems(Status status) {
        this.status = status;
        this.items = null;
    }

    public Status getStatus() {
        return status;
    }

    public void setStatus(Status status) {
        this.status = status;
    }

    public T getItems() {
        return items;
    }

    public void setItems(T items) {
        this.items = items;
    }
}

Все, что я хочу сделать, это проверить, является ли параметр T списком любого типа в конструкторах. Если T является List <>, я хочу создать его экземпляр в новом List <> ();

Я пробовал следующий код

if (this.items instanceof List) {
    this.items = Collections.emptyList();
}

или это

this.items = new ArrayList<>();

Но я продолжаю получать сообщение об ошибке, потому что не могу указать тип параметра. Как мне убедиться, что я создаю экземпляры элементов с новым списком, если общий тип T является списком?

Если вы планируете жестко закодировать зависимость от списка, то почему бы просто не использовать NetworkItems<List>?

Tim Biegeleisen 02.05.2018 13:15

Потому что контейнер должен иметь возможность размещать как список элементов, так и отдельный элемент.

Sriram R 02.05.2018 13:28

@SriramR Поскольку контейнер должен иметь возможность размещать как список элементов, так и отдельный элемент - зачем? Почему бы не иметь два разных контейнера для одного предмета или набора предметов?

lexicore 02.05.2018 13:39

Я не хотел повторять код. Реализация такая же. За исключением Т-части. Поэтому я подумал, если есть способ обойтись без повторения кода, почему бы этого не сделать?

Sriram R 02.05.2018 13:49
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
4
68
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Дайте классу необязательный аргумент конструктора типа Supplier<T>.

public class NetworkItems<T> {

    private Status status;
    private T items;
    private Supplier<T> defaultCreator;

    public NetworkItems(Supplier<T> def) {
        this.status = Status.FAILURE;
        this.items = null;
        this.defaultCreator = def;
    }

    public T createDefault() {
        return defaultCreator.get();
    }
    // ...

Теперь, если у вас есть экземпляр NetworkItems, вы всегда можете получить значение по умолчанию. Например,

NetworkItem<List<String>> stringListItems = new NetworkItem<>(ArrayList::new);
List<String> defItem = stringListItems.createDefault();

Вы можете просто добавить приведение типа, тогда оно должно работать, как вы уже сказали:

if (this.items instanceof List) {
    this.items = (T) Collections.emptyList();
}

Выдает предупреждение UncheckedCastException.

Sriram R 02.05.2018 13:25

Да, это правда, но я думаю, что вы не можете предотвратить это, если используете такую ​​универсальную переменную-член, потому что конструктор не может знать во время компиляции, какой тип вы хотите там использовать. Возможно, вы можете использовать другой подход, вместо этого, используя только T items, вы можете напрямую использовать список List<T> items;, в который вы добавляете свои элементы.

Ehler 02.05.2018 13:31

Кроме того, даже если T - это List<Something>, this.items все еще может быть null, поэтому instanceof не сильно поможет.

lexicore 02.05.2018 13:38

Да, я использовал его раньше как List <T>. Дело в том, что я хочу, чтобы этот контейнер мог содержать List <> и Object. Поэтому я просто хотел узнать, возможно ли это без написания нового держателя.

Sriram R 02.05.2018 14:08

Судя по комментариям в этом документе и вашему исходному сообщению, кажется, что items задуман как коллекция, независимо от вашей ситуации. Разве вам не лучше было бы сделать следующее?

  public class NetworkItems<T> {

    private Status status;
    private List<T> items;

    //continue the remainder of your implementation here 
  }

Я понимаю, что это не идеально для сценария, в котором может существовать 1 элемент, но вы обеспечиваете безопасность типов здесь и придерживаетесь концепции, что это может быть один или несколько элементов, создавая items коллекцию.

Другие вопросы по теме