ArrayList<? extends A> array = new ArrayList<A>();
array.add(new A());
Почему это не скомпилировано?
Соответствующая часть из учебника Java (http://docs.oracle.com/javase/tutorial/java/generics/wildcardGuidelines.html):
Список, определенный списком, может быть неофициально считаться только для чтения, но это не является строгой гарантией. Предположим, у вас есть следующие два класса:
class NaturalNumber { private int i; public NaturalNumber(int i) { this.i = i; } // ... } class EvenNumber extends NaturalNumber { public EvenNumber(int i) { super(i); } // ... }
Рассмотрим следующий код:
List<EvenNumber> le = new ArrayList<>(); List<? extends NaturalNumber> ln = le; ln.add(new NaturalNumber(35)); // compile-time error
Поскольку
List<EvenNumber>
является подтипомList<? extends NaturalNumber>
List<? extends NaturalNumber>
, вы можете назначить le для ln. Но вы не можете использовать ln для добавления натурального числа в список четных чисел.Возможны следующие операции в списке:
- Вы можете добавить null.
- Вы можете использовать clear.
- Вы можете получить итератор и вызывать удаление.
- Вы можете захватить подстановочный знак и записать элементы, которые вы прочитали из списка.
Вы можете видеть, что список, определенный List, не доступен только для чтения в строгом смысле этого слова, но вы можете подумать об этом так, потому что вы не можете сохранить новый элемент или изменить существующий элемент в списке.
Другое соответствующее объяснение можно найти здесь (его ссылка также объясняет проблему подстановочных знаков - http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html):
...
Однако небезопасно добавлять к нему произвольные объекты:
Collection<?> c = new ArrayList<String>(); c.add(new Object()); // Compile time error
Поскольку мы не знаем, что означает тип элемента c, мы не можем добавлять к нему объекты. Метод add() принимает аргументы типа E, тип элемента коллекции. Когда фактический параметр типа есть?, Это означает какой-то неизвестный тип. Любой параметр, который мы передаем для добавления, должен быть подтипом этого неизвестного типа. Поскольку мы не знаем, что это такое, мы ничего не можем передать. Единственным исключением является null, который является членом каждого типа.
С другой стороны, учитывая List, мы можем вызвать get() и использовать результат. Тип результата - неизвестный тип, но мы всегда знаем, что это объект. Поэтому безопасно назначать результат get() переменной типа Object или передавать его как параметр, где ожидается тип Object.
Вы не можете добавить A
в List<? extends A>
List<? extends A>
. Чтобы исправить вашу проблему, вы должны просто объявить свой список как
ArrayList<A> array = new ArrayList<A>();
Обратите внимание, что предпочтительнее использовать интерфейс для объявления:
List<A> array = new ArrayList<A>();
Это позволяет вам легко изменить конкретный тип позднее, потому что вам нужно только сделать одно изменение.
array.add(new A());
проблема в том, что объект A
нельзя добавить в List<? extends A>
Поскольку мы не знаем, что означает тип элемента массива, мы не можем добавлять к нему объекты.
Вместо этого используйте временный список:
ArrayList<A> tempArray = new ArrayList<A>();
tempArray.add(new A())
tempArray.add(new A())
ArrayList<? extends A> array = tempArray;
Пример использования
//Средство передвижения
public abstract class Vehicle {
}
//Автомобиль
public class Car extends Vehicle {
}
//HandlerVehicle
public class HandlerVehicle {
private List<? extends Vehicle> _vehicles;
public void addVehicles(List<? extends Vehicle> vehicles) {
_vehicles = vehicles;
//perform operations with Vehicle objects
}
}
//HandlerCar
public class HandlerCar {
private HandlerVehicle _handlerVehicle;
private List<Car> _cars;
public HandlerCar() {
_cars = getCars();
_handlerVehicle = new HandlerVehicle();
_handlerVehicle.addVehicles(_cars);
}
private List<Car> getCars() {
return new ArrayList<Car>();
}
}
ArrayList
и назначаете его на ссылку genericArray
. Затем продолжите отбрасывать новый список, назначив genericArray
для ссылки на тот же список, что и array
.
tempArray
, поэтому array
самом деле не нужен. Конечно, может быть, я упускаю причину сделать это.