У меня есть общий класс, похожий на этот
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 является списком?
Потому что контейнер должен иметь возможность размещать как список элементов, так и отдельный элемент.
@SriramR Поскольку контейнер должен иметь возможность размещать как список элементов, так и отдельный элемент - зачем? Почему бы не иметь два разных контейнера для одного предмета или набора предметов?
Я не хотел повторять код. Реализация такая же. За исключением Т-части. Поэтому я подумал, если есть способ обойтись без повторения кода, почему бы этого не сделать?
Дайте классу необязательный аргумент конструктора типа 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.
Да, это правда, но я думаю, что вы не можете предотвратить это, если используете такую универсальную переменную-член, потому что конструктор не может знать во время компиляции, какой тип вы хотите там использовать. Возможно, вы можете использовать другой подход, вместо этого, используя только T items
, вы можете напрямую использовать список List<T> items;
, в который вы добавляете свои элементы.
Кроме того, даже если T
- это List<Something>
, this.items
все еще может быть null
, поэтому instanceof
не сильно поможет.
Да, я использовал его раньше как List <T>. Дело в том, что я хочу, чтобы этот контейнер мог содержать List <> и Object. Поэтому я просто хотел узнать, возможно ли это без написания нового держателя.
Судя по комментариям в этом документе и вашему исходному сообщению, кажется, что items
задуман как коллекция, независимо от вашей ситуации. Разве вам не лучше было бы сделать следующее?
public class NetworkItems<T> {
private Status status;
private List<T> items;
//continue the remainder of your implementation here
}
Я понимаю, что это не идеально для сценария, в котором может существовать 1 элемент, но вы обеспечиваете безопасность типов здесь и придерживаетесь концепции, что это может быть один или несколько элементов, создавая items
коллекцию.
Если вы планируете жестко закодировать зависимость от списка, то почему бы просто не использовать
NetworkItems<List>
?