我有一个List,声明如下:
List<? extends Number> foo3 = new ArrayList<Integer>();
我试图将3添加到foo3。但是我收到如下错误消息:
The method add(capture#1-of ? extends Number) in the type List<capture#1-of ?
extends Number> is not applicable for the arguments (ExtendsNumber)
答案 0 :(得分:275)
抱歉,但你不能。
List<? extends Number> foo3
的通配符声明意味着变量foo3
可以保存一系列类型中的任何值(而不是特定类型的任何值)。这意味着其中任何一项都是合法的任务:
List<? extends Number> foo3 = new ArrayList<Number>; // Number "extends" Number
List<? extends Number> foo3 = new ArrayList<Integer>; // Integer extends Number
List<? extends Number> foo3 = new ArrayList<Double>; // Double extends Number
因此,考虑到这一点,您可以添加哪种类型的对象List foo3
,这些对象在上述任何ArrayList
任务之后都是合法的:
Integer
,因为foo3
可能指向List<Double>
。Double
,因为foo3
可能指向List<Integer>
。Number
,因为foo3
可能指向List<Integer>
。 您无法向List<? extends T>
添加任何对象,因为您无法保证它真正指向的是哪种List
,因此您无法保证该对象被允许在那List
。唯一的“保证”是您只能从中读取,并且您将获得T
的{{1}}或子类。
反向逻辑适用于T
,例如super
。这些是合法的:
List<? super T>
您无法从List<? super Number> foo3 = new ArrayList<Number>; // Number is a "super" of Number
List<? super Number> foo3 = new ArrayList<Object>; // Object is a "super" of Number
读取特定类型T(例如Number
),因为您无法保证它真正指向的List<? super T>
类型。您唯一的“保证”是,您可以添加List
类型的值(或T
的任何子类),而不会违反所指向列表的完整性。
完美的例子是T
的签名:
Collections.copy()
注意public static <T> void copy(List<? super T> dest,List<? extends T> src)
列表声明如何使用src
允许我从一系列相关List类型中传递任何List,并且仍然保证它将生成T类型或T的子类的值。但是你无法添加到extends
列表。
src
列表声明使用dest
允许我从一系列相关List类型中传递任何List,并且仍然保证我可以将特定类型T的值写入该列表。但如果从列表中读取,则无法保证读取特定类型T的值。
现在,感谢泛型通配符,我可以使用这种方法进行任何调用:
super
考虑这个令人困惑且非常宽泛的代码来锻炼你的大脑。注释掉的行是非法的,其原因是在行的最右侧(需要滚动查看其中一些):
// copy(dest, src)
Collections.copy(new ArrayList<Number>(), new ArrayList<Number());
Collections.copy(new ArrayList<Number>(), new ArrayList<Integer());
Collections.copy(new ArrayList<Object>(), new ArrayList<Number>());
Collections.copy(new ArrayList<Object>(), new ArrayList<Double());
答案 1 :(得分:14)
你不能(没有不安全的演员表)。你只能从中读取。
问题是你不知道列表的确切列表是什么。它可以是Number的任何子类的列表,因此当您尝试将元素放入其中时,您不知道该元素实际上适合列表。
例如,列表可能是Byte
的列表,因此将Float
放入其中会出错。
答案 2 :(得分:2)
你可以这样做:
List<Number> foo3 = new ArrayList<Number>();
foo3.add(3);
答案 3 :(得分:1)
即使我在这里阅读了答案,也一直让我感到困惑,直到我发现了帕维尔·米纳耶夫(Pavel Minaev)的评论:
请注意列表<?扩展Number>并不意味着“对象列表 不同的类型,所有这些类型都以Number扩展。”表示“ 扩展Number的单一类型的对象”
在此之后,我能够理解BertF的出色解释。列表<?扩展Number>是什么意思?可以是扩展Number(Integer,Double等)的任何类型,并且声明中的未清除(列表<?extended Number> list)是哪种类型,因此当您想使用add方法时不知道输入是否具有相同的类型;到底是什么类型?
那么List <的元素扩展Number>只能在构造时设置。
还要注意这一点:当我们使用模板时,我们告诉编译器我们弄乱了什么类型。例如, T 会为我们保留该类型,但?不会一样
我得说..这是一个要解释/学习的肮脏的东西之一
答案 4 :(得分:0)
&#34;列出&#39;&lt;&#39; ? extends Number&gt;实际上是上限通配符!
上限通配符表示任何扩展Number或Number本身的类都可以用作形式参数类型: 问题源于 Java不知道List 究竟是什么类型的事实。 它必须是一个精确和独特的类型。我希望它有所帮助:)
答案 5 :(得分:0)
您可以通过创建对列表的其他类型的引用来捏造它。
(这些是sepp2k提到的“不安全的强制转换”。)
List<? extends Number> list = new ArrayList<Integer>();
// This will not compile
//list.add(100);
// WORKS, BUT NOT IDEAL
List untypedList = (List)list;
// It will let you add a number
untypedList.add(200);
// But it will also let you add a String! BAD!
untypedList.add("foo");
// YOU PROBABLY WANT THIS
// This is safer, because it will (partially) check the type of anything you add
List<Number> superclassedList = (List<Number>)(List<?>)list;
// It will let you add an integer
superclassedList.add(200);
// It won't let you add a String
//superclassedList.add("foo");
// But it will let you add a Float, which isn't really correct
superclassedList.add(3.141);
// ********************
// So you are responsible for ensuring you only add/set Integers when you have
// been given an ArrayList<Integer>
// ********************
// EVEN BETTER
// If you can, if you know the type, then use List<Integer> instead of List<Number>
List<Integer> trulyclassedList = (List<Integer>)(List<?>)list;
// That will prevent you from adding a Float
//trulyclassedList.add(3.141);
System.out.println("list: " + list);
由于untypedList
,superclassedList
和trulyclassedList
只是对list
的引用,因此您仍将元素添加到原始ArrayList中。
在上面的示例中,您实际上并不需要使用(List<?>)
,但是您可能需要在代码中使用它,具体取决于获得的list
的类型。
请注意,使用?
会向您发出编译器警告,直到将其放在函数上方:
@SuppressWarnings("unchecked")
答案 6 :(得分:0)
因为3是primitive (int)
,没有扩展Number
,所以可以加上它的装箱类型(Integer.valueOf(3))
。虽然在IDEA
中显示为错误,但仍然可以正常执行。
答案 7 :(得分:-1)
从'Object'扩展列表的地方,可以使用list.add;当要使用list.get时,只需将Object强制转换为对象;