列表中的通配符 - Java泛型

时间:2014-09-07 08:12:50

标签: java generics

ArrayList<? extends A> array = new ArrayList<A>();
array.add(new A());

为什么不编译?

3 个答案:

答案 0 :(得分:4)

Java教程中的相关部分(http://docs.oracle.com/javase/tutorial/java/generics/wildcardGuidelines.html):

  

List定义的列表可以非正式地被认为是   只读,但这不是严格的保证。假设你有   以下两节课:

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>的子类型,因此您可以将le指定给ln。但你不能使用ln来添加   偶数列表的自然数。

     

列表中的以下操作是可能的:

     
      
  • 您可以添加null。
  •   
  • 您可以调用清除。
  •   
  • 您可以获取迭代器并调用remove。
  •   
  • 您可以捕获通配符并写入您从列表中读取的元素。
  •   
     

您可以看到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类型的变量或将其作为参数传递给   类型对象是预期的。

答案 1 :(得分:0)

您无法将A添加到List<? extends A>。为了解决您的问题,您只需将列表声明为

即可
ArrayList<A> array = new ArrayList<A>();

请注意,最好使用声明接口:

List<A> array = new ArrayList<A>();

这使您可以在以后轻松更改具体类型,因为您只需要进行一次更改。

答案 2 :(得分:0)

由于we don't know数组的元素类型代表什么,我们无法向其添加对象。

相反,请使用临时列表:

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>();
    }
}