我正在准备考试,教授给我们的一个代码对我来说是模糊的:
public class Z {
static java.util.LinkedList<? extends Object> a =
new java.util.LinkedList<String>();
public static void main(String[] args) {
a.add(null); // 1
a.add(new Object()); // 2
a.add("new Object()"); // 3
System.out.println(a); // 4
}
}
Run Code Online (Sandbox Code Playgroud)
NetBeans在这里给我带来了非常奇怪的编译错误:
no suitable method found for add(java.lang.Object)
method java.util.LinkedList.add(capture#1 of ? extends java.lang.Object) is not applicable
(actual argument java.lang.Object cannot be converted to capture#1 of ? extends java.lang.Object by method invocation conversion)
no suitable method found for add(java.lang.String)
method java.util.LinkedList.add(capture#2 of ? extends java.lang.Object) is not applicable
(actual argument java.lang.String cannot be converted to capture#2 of ? extends java.lang.Object by method invocation conversion)
Run Code Online (Sandbox Code Playgroud)
有人可以解释一下这些错误吗?我很确定应该可以将String对象添加到此列表中.
PECS - 生产者扩展,消费者超级 - 这是布洛赫提出的一个助记符,以应对上述问题.
换句话说,如果您使用extends,则只能从您的集合中生成元素.如果你想要它消耗元素 - 使用super.
重点是强制编译时安全.如果您的集合是使用定义的? extends SomeBaseClass,那么这将意味着"它可以包含基类的单个子类的实例".在您定义的情况下 new LinkedList<String>(),但是您尝试添加Object- 这不应该被允许,并且它被编译器捕获.
在调用时a.add(),java只知道你调用add java.util.LinkedList<? extends Object>.此时链接列表String未知.您可以在上一行添加另一个链接列表与任何其他类型.
所有java都知道该列表包含的内容extends Object.这可能是任何事情,因为java中的每个类都扩展了对象.
a = new java.util.LinkedList<Object>(); // valid
a = new java.util.LinkedList<Integer>(); // valid
a = new java.util.LinkedList<java.util.zip.Checksum>(); // valid
Run Code Online (Sandbox Code Playgroud)
请注意,由于a可以包含任何链接列表,因此无法向其添加任何内容.如果你添加一个Object,列表可能是期待的Integer.如果你添加一个Integer,它可能是期待的Checksum.
你写的是同样的问题
static java.util.LinkedList<? extends Number> b = new java.util.LinkedList<Integer>();
Run Code Online (Sandbox Code Playgroud)
然后:
b.add(new Float(10.0f)); // fails
b.add(new Integer(10)); // fails
Run Code Online (Sandbox Code Playgroud)
Java仍然不知道列表是否包含Floats或Integers,因此它禁止这两者.
声明列表的正确方法是:
static java.util.LinkedList<? super Number> c = new java.util.LinkedList<Number>(); // valid
static java.util.LinkedList<? super Number> c = new java.util.LinkedList<Object>(); // valid
Run Code Online (Sandbox Code Playgroud)
以下代码现在将失败:
static java.util.LinkedList<? super Number> c = new java.util.LinkedList<Integer>(); // fails
Run Code Online (Sandbox Code Playgroud)
因为现在c不能包含List<Integer>,添加一个Float将是有效的.
编辑:返回原始示例.如何在a上使用add函数有一种有点邪恶的方法List<? extends Object>
public static void main(String[] args) {
a.add(null); // 1
((List<Object>)a).add(new Object()); // 2
((List<Object>)a).add("new Object()"); // 3
System.out.println(a); // 4
}
Run Code Online (Sandbox Code Playgroud)
注意事项2和3将给出未经检查的投射警告.你冒着堆污染的风险,事实上,案例2确实如此.