我经历了这些话题
但是,我似乎仍然丢失了super关键字:
当我们声明一个这样的集合时:
List<? super Number> list = null;
list.add(new Integer(0));//this compiles
list.add(new Object());//this doesn't compile
Run Code Online (Sandbox Code Playgroud)
不应该是相反的 - 我们有一个列表,其中包含一些父母的对象(未知类型)Number.所以Object应该适合(因为它是父的Number),Integer不应该.出于某种原因,情况正好相反.
只要我们有以下代码
static void test(List<? super Number> param) {
param.add(new Integer(2));
}
public static void main(String[] args) {
ArrayList<String> sList = new ArrayList<String>();
test(sList); //will never compile, however...
}
Run Code Online (Sandbox Code Playgroud)
编译上面的代码是不可能的(我的理智表明这是正确的行为),但基本逻辑可能证明相反:
String is Object, Object is superclass of Number. So String should work.
我知道这很疯狂,但这不是他们不允许<S super T>构造的原因吗?如果是,那么为什么<? super T>允许?
有人可以帮我恢复这个逻辑链的缺失部分吗?
pol*_*nts 95
有界通配符List<? super Number>可以捕获Number及其任何超类型.因为Number extends Object implements Serializable,这意味着目前可捕获的唯一类型List<? super Number>是:
List<Number>List<Object>List<Serializable>请注意,您可以add(Integer.valueOf(0))使用上述任何类型.但是,您不能 add(new Object())使用a List<Number>或a List<Serializable>,因为这违反了通用类型安全规则.
因此,它是不是真的,你可以add任意超Number到List<? super Number>; 这根本不是限制通配符和捕获转换的工作方式.你没有声明一个,List<? super Number>因为你可能想要添加一个Object(你不能!); 你这样做是因为你想要向Number它添加对象(即它是"消费者" Number),而且只是一个List<Number>限制太多.
extends,消费者 -supernew Integer(0)vs valueOf等Col*_*ert 21
对于第一部分List<Number>适合,List<? super Number>但你不能添加Object到List<Number>.这就是为什么你不能将添加Object到List<? super Number>.
另一方面,您可以将Number(Number包含)的每个子类添加到列表中.
对于第二部分,String是一个Object,但String不是一个超类Number.
如果它像这样工作,因为每个类都是子类Object,super就没有任何意义.
List<? super Number>:List<Object>
List<Object> 将工作Object 适合 <? super Number>Number到aList<Object>String它,您唯一可以确定的是可以添加任何子类Number.List<Number>:
List<Number> 将工作Number 适合 <? super Number>Number到aList<Number>List<Integer>(或任何子类Number):
List<Integer> 不行Number所以它正是我们想要避免的Integer在一个适合Number你不会abble添加的任何子类Number中List<Integer>(例如Float)super 并不意味着一个子类.List<String>(或任何不扩展的类,Number也不在Number(Number和.Object)的"超级层次结构"中:
List<String> 不行String不适合Number"超级层次结构"String在配合Object(这是一个超类的Number),你woudln't一定要能够将添加Number到List包含来自超类的一个任何子类Number)super 并不意味着其中一个超类的任何子类,它只是一个超类.它是如何工作的 ?
您可以说,只要您可以添加任何Number类型的子类List,它就会尊重super关键字.
小智 6
List<? super Number>意味着变量的引用类型表明我们有一个数字、对象或序列化列表。
无法添加对象的原因是因为编译器不知道这些类中的哪些类位于实际实例化对象的通用定义中,因此它只允许您传递 Number 或 Number 的子类型,例如 Double、Integer 和很快。
假设我们有一个返回List<? super Number>. 从我们的角度来看,方法内部对象的创建是封装的,我们只是不能说它是否是这样的:
List<? super Number> returnValue = new LinkedList<Object>();
或者
List<? super Number> returnValue = new ArrayList<Number>();
因此,泛型类型可以是“对象”或“数字”。在这两种情况下,我们都可以添加 Number,但只有在一种情况下,我们才可以添加 Object。
在这种情况下,您必须区分引用类型和实际对象类型。
我有一段时间没有得到它。这里的许多答案以及其他问题专门显示某些用法在何时何地是错误的,但原因不多。
这就是我最终得到它的方式。如果我有一个将Numbers 添加到的函数,则List可能要添加它们的类型MySuperEfficientNumber,这是我自己实现的自定义类Number(但不是的子类Integer)。现在,调用者可能不了解MySuperEfficientNumber,但是只要知道将添加到列表中的元素视为没有比特定的元素Number,它们就可以了。
如果我将我的方法声明为:
public static void addNumbersToList(List<? extends Number> numbers)
Run Code Online (Sandbox Code Playgroud)
然后,呼叫者可以传递List<Integer>。如果我的方法MySuperEfficientNumber在的末尾添加a numbers,则调用方将不再具有的List,Integer并且以下代码将不起作用:
List<Integer> numbers = new ArrayList<Integer>();
addNumbersToList(numbers);
// The following would return a MySuperEfficientNumber not an Integer
Integer i = numbers.get(numbers.size()-1)
Run Code Online (Sandbox Code Playgroud)
显然这是行不通的。错误将在addNumbersToList方法内部。您会得到类似:
The method add... is not applicable for the arguments (MySuperEfficientNumber)
Run Code Online (Sandbox Code Playgroud)
因为numbers可以是任何特定种类的Number,不一定MySuperEfficientNumber是与之兼容的东西。如果我将声明翻转为use super,则该方法将编译而不会出错,但调用者的代码将失败并显示以下内容:
The method addNumbersToList(List<? super Number>)... is not applicable for the arguments (List<Integer>)
Run Code Online (Sandbox Code Playgroud)
因为我的方法是说:“别以为您List可以比...更具体Number。我可以Number在列表中添加各种怪异的东西,您只需要处理它即可。如果您想起它们如一些更普遍比Number-喜欢Object-这很好,我保证他们会至少NumberS,但你可以更一般地,如果你想对待他们“。
而extends说:“ List只要您每个元素至少一个,我都不会在乎您给我什么样的东西Number。它可以是任何一种Number,甚至您自己的怪异,习俗,虚构的东西Number。他们实现了该接口,我们很好。我不会在您的列表中添加任何内容,因为我不知道您在那里使用的是什么实际的具体类型。”