Java中的泛型和通配符

时间:2018-12-15 18:38:22

标签: java generics wildcard

我最近参加了一门有关泛型和通配符的Java课程。我无法把握它们之间的区别,有时甚至无法使用它们。

请回答两个问题:

1)订单包含产品列表,而我们将床单和夹子作为产品。

public class Product {}

public class Sheet extends Product{}

public class Clip extends Product{}

public class Order {
    //isn't this:
    private List<Product> products;

    //same as this:
    private List<? extends Product> products;
}

2.1)使用第一个(List<Product>)时:

public Order() {//Order constructor, trying to create an order of sheets

    this.products = new ArrayList<Sheet>();//compiler asks for cast
}

如果我尝试不进行任何转换就进行编译,则错误提示:

  

不可编译的源代码-不兼容的类型:   java.util.ArrayList 不能转换为   java.util.List <产品>

然后,如果我这样做,则发生事件:

public Order(){
     products = new ArrayList<>();
     products.add(new Sheet()); //again asks for a cast
}

无论如何尝试编译,错误提示:

  

不可编译的源代码-错误的符号类型:java.util.List.add

2.2)使用第二个(List<? extends Product>)时:

public Order(){// Order构造函数,试图创建工作表订单

    this.products = new ArrayList<Sheet>();//compiler asks for cast as well
}

如果我尝试不进行任何转换就进行编译,则错误提示:

  

不兼容的类型:java.util.ArrayList 无法转换   到java.util.List <?扩展产品>

然后,如果我这样做,则发生事件:

public Order(){
     products = new ArrayList<>();
     products.add(new Sheet()); //no suitable method found for add(Sheet), 
                                //method Collection.add(CAP#1) is not applicable
}

无论如何尝试编译,错误提示:

  

不可编译的源代码-错误的符号类型:java.util.List.add

2 个答案:

答案 0 :(得分:3)

变量声明的类型应与您在实际对象类型中传递的类型匹配。所以:

List<Product> list = new ArrayList<Clip>();

OR

 List<Product> list = new ArrayList<Sheet>(); 

无法编译。

其背后的原因是,您可能最终将Clip对象放在应该仅包含Sheets的列表中,并最终最终将其视为Sheet。

开发人员似乎很困惑,因为在使用数组的情况下允许这样做。

Product[] array = new Sheet[10]; // Compiles fine

在数组的情况下是允许的,因为有一个运行时异常(ArrayStoreException),可以防止您在数组中放置错误类型的对象。 (考虑对上述数组执行此操作:array[0] = new Clip();

对于列表,没有同等的例外,因为JVM在运行时知道Array的类型,但由于类型擦除,所以不知道List。

此外,private List<Product> products;不等同于private List<? extends Product> products,因为您可以在private List<Product> products;中添加任何产品或产品的子类型,但不能添加任何内容({{1 }})到null。当您要将列表传递给仅从列表中读取数据的方法时,通常使用此语法。如下所示:

private List<? extends Product> products

此方法将同时接受private void readProduct(List<? extends Product> list){ //read product list } List<Clip>。但是,向其中添加任何内容都会导致编译错误(null除外)。

答案 1 :(得分:1)

ArrayList<Sheet>不是ArrayList<Product>的子类型。

您不能在期望ArrayList<Product>的任何地方使用它,尤其是在ArrayList<Product>中,您可以合法地添加Clip,但是您不应该使用{{1 }}。