我试图理解java generic covariancy,我理解为什么
<div class="main">
是不允许的,因此不会将浮动放入列表中,从而导致问题。我相信类型擦除会将其编译为:
List<Number> list = new ArrayList<Integer>();
Integer = list.get(0);
这是允许的:
List list = new ArrayList();
Integer = (Integer) list.get(0);
在类型擦除后,这还没有编译成同样的东西吗? 通配符如何帮助编译器强制浮点数在保存整数时不会被放入列表中?
答案 0 :(得分:5)
如果您有List<? extends Number> list
,则无法将任何放入结果列表中。您的列表是&#34;列表,其中包含一些扩展Number
&#34;的对象,因此使用任何参数调用add()
与此类型不兼容。所以这就是编译器控制你是否放置浮动的方式:它不允许放任何东西。
通常只在您不打算修改列表的地方将类型更改为List<? extends Number>
,并且只想阅读它。
答案 1 :(得分:1)
Tagir非常好的回答,我想补充几点。 首先,以下内容甚至不会编译:
List<? extends Number> list = new List<Integer>();
我希望你知道List
是一个界面。所以现在我们有:
List<? extends Number> list = new ArrayList<Integer>();
此处list
是List<? extends Number>
类型的引用,它只是意味着它可以引用一个列表,其中每个元素 IS Number
或更具体地说每个元素element扩展了类Number
,因此它意味着允许以下所有内容:
list = new ArrayList<Float>();
list = new ArrayList<Long>();
但我们无法将Object
列为Object
,而Number
不是list = new ArrayList<Object>(); // compile time error
。
Number
现在,当我们从这个列表中取出元素时,我们只知道有一件事情确定它是Integer
,这意味着不确定但它可以是Long
或{{1}也是。所以我们需要铸造:
Integer integer = (Integer) list.get(0);
Float floatValue = (Float) list.get(0);
Number number = list.get(0); // no casting if assigning it to Number
当我们生成元素而不消耗它们时,这非常有用(检查PECS)。例如,在打印元素时很有用,但是当你想在其中添加任何元素时它们没用,因为它甚至都不会编译。
private static void printMe(List<? extends Number> numbers) {
for(Number number : numbers) {
System.out.println(number);
}
}
这可以调用为:
List<Integer> integerList = new ArrayList<>();
integerList.add(10);integerList.add(20);integerList.add(30);
printMe(integerList);
List<Long> longList = new ArrayList<>();
longList.add((long) 4.5);longList.add((long) 6.5);longList.add((long) 7.5);
printMe(longList);
这将只打印每个列表中的元素。