我最近参加了一门有关泛型和通配符的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
答案 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 }}。