javagenerics超级关键字
我经历了这些话题
- generics..? 超级T
- 用“超级”关键字绑定generics
但是,我似乎仍然是super关键词丢失:
-
当我们宣布这样一个集合:
List<? super Number> list = null; list.add(new Integer(0));//this compiles list.add(new Object());//this doesn't compile不应该是相反的 – 我们有一个列表,其中包含一些对象(未知types),它们是
Number父项。 所以Object应该适合(因为它是数字的父亲),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... }编写上面的代码是不可能的(我的理智认为这是正确的行为),但基本逻辑可能certificate是相反的:
String is Object, Object is superclass of Number. So String should work.我知道这很疯狂,但是这不是他们不允许
<S super T>构造的原因吗? 如果是,那么为什么<? super T><? super T>是允许的?
有人能帮助我恢复这个逻辑链中缺less的部分吗?
List<? super Number>的有界通配符 List<? super Number>可以捕获Number及其任何超types。 由于Number extends Object implements Serializable ,这意味着唯一的types,目前捕获可转换的List<? super Number> List<? super Number>是:
-
List<Number> -
List<Object> -
List<Serializable>
请注意,您可以add(Integer.valueOf(0))到上述任何types中。 但是,您不能 add(new Object())到List<Number>或List<Serializable> ,因为这违反了通用types安全规则。
因此,你可以add任何超types的Number到一个List<? super Number> List<? super Number> ; 这根本不是多么有界的通配符和捕捉转换工作。 你不要声明一个List<? super Number> List<? super Number>因为你可能想添加一个Object (你不能!); 你这样做是因为你想添加Number对象(即它是Number的“消费者”),而List<Number>太简单了。
参考
- Angelika Langer的generics常见问题
- 什么是有界通配符?
- 什么时候使用带有下限的通配符参数化types? (“当一个具体的参数化types太严格了。”)
- 为什么没有types参数的下限? (“因为它没有意义。”)
- JLS 5.1.10捕捉转换
也可以看看
- Effective Java第2版 ,第28项:使用有界通配符来增加API的灵活性
- “PECS代表生产者
extends,super消费者
- “PECS代表生产者
相关问题
- 太多的列表,PECS,
new Integer(0)和valueOf等等
对于第一部分List<Number>适合List<? super Number> List<? super Number>但不能将Object添加到List<Number> 。 这就是为什么你不能添加一个Object List<? super Number> List<? super Number> 。
另一方面,您可以将Number ( Number included)的每个子类添加到列表中。
对于第二部分, String是一个Object ,但String不是Number的超类。
如果这样工作,因为每个类都是Object的子类, super就没有意义了。
让我们看看List<? super Number>每个可能的情况 List<? super Number> :
- 传递的列表是一个
List<Object>-
List<Object>将工作 -
Object适合<? super Number><? super Number> - 您可以将任何数字的子types添加到
List<Object> - 即使你也可以在其中添加
String,唯一可以确定的是你可以添加Number任何子类。
-
- 传递的列表是一个
List<Number>:-
List<Number>将工作 -
Number适合<? super Number><? super Number> - 您可以将任何数字的子types添加到
List<Number>
-
- 传递的列表是
List<Integer>(或Number任何子类):-
List<Integer>将不起作用 - 整数是
Number一个子类,所以它正是我们想要避免的 - 即使一个
Integer适合一个Number你也不能在一个List<Integer>(例如一个Float)中添加任何Number子类, -
super并不意味着一个子类。
-
- 传递的列表是一个
List<String>(或者任何没有扩展Number类,也不是Number的“超级层次”(即Number和Object):-
List<String>不起作用 -
String不适合Number“超级层次” - 即使
String适合Object(它是Number一个超类),您也不一定能够将Number添加到包含来自Number的超类之一的任何子类的List) -
super并不意味着其中一个超类的任何子类,它只意味着超类中的一个。
-
它是如何工作的 ?
你可以说,只要你可以添加任何types的List子类,它尊重super关键字。
我有同样的问题。 我认为语法是混乱的原因。
List<? super Number> List<? super Number>似乎提示“ 超级types的数字列表 ”,但它实际上意味着什么是“ 列表中的数字作为超types的东西 ”。
一旦我开始阅读,就像这样点击。
List<? super Number> List<? super Number>表示variables的引用types表明我们有一个Numbers,Objects或Serializables的列表。
你不能添加一个Object的原因是因为编译器不知道这些类中的WHICH是否在实际实例化对象的通用定义中,所以它只允许你传递Number或者Number的子types,比如Double,Integer和等等。
比方说,我们有一个方法返回一个List<? super Number> List<? super Number> 。 方法内部的对象的创build是从我们的视图封装的,我们不能说是否是这样的:
List<? super Number> returnValue = new LinkedList<Object>();
要么
List<? super Number> returnValue = new ArrayList<Number>();
所以,genericstypes可以是Object或Number。 在这两种情况下,我们都可以添加Number,但只有在一种情况下,我们才可以添加Object。
在这种情况下,你必须区分引用types和实际的对象types。
List<? super Number> List<? super Number>就是这样一个List<AncestorOfNumber> ,我们可以隐式地将每个Number为它的超typesAncestorOfNumber 。
考虑这个:什么genericstypes需要???? 在下面的例子中?
InputStream mystream = ...; void addTo(List<????> lsb) { lsb.add(new BufferedInputStream(mystream)); } List<BufferedInputStream> lb = new ArrayList<>(); List<InputStream> li = new ArrayList<>(); List<Object> lo = new ArrayList<>(); ... { addTo(lb); addTo(li); addTo(lo); }
答案是: 是什么我们可以投入BufferedInputStream ,这是非常相同的或其祖先之一: ? super BufferedInputStream ? super BufferedInputStream
我没有得到它一段时间。 这里的许多答案和其他问题具体显示何时何地某些用法是错误的,但不是那么多的原因。
这是我终于明白的。 如果我有一个函数将Number添加到List ,我可能想要添加他们的typesMySuperEfficientNumber这是我自己的自定义类实现Number (但不是Integer的子类)。 现在调用者可能不知道任何有关MySuperEfficientNumber ,但只要他们知道将添加到列表中的元素视为没有比Number更具体的特性,他们就可以。
如果我将我的方法声明为:
public static void addNumbersToList(List<? extends Number> numbers)
然后调用者可以传递一个List<Integer> 。 如果我的方法在numbers的末尾添加了MySuperEfficientNumber ,则调用者将不再具有Integer List ,下面的代码将不起作用:
List<Integer> numbers = new ArrayList<Integer>(); addNumbersToList(numbers); // The following would return a MySuperEfficientNumber not an Integer Integer i = numbers.get(numbers.size()-1)
显然这是行不通的。 而这个错误会在addNumbersToList方法中。 你会得到像这样的东西:
The method add... is not applicable for the arguments (MySuperEfficientNumber)
因为numbers可以是任何特定types的Number ,不一定是MySuperEfficientNumber兼容的东西。 如果我翻转声明来使用super ,该方法将编译没有错误,但调用者的代码将失败:
The method addNumbersToList(List<? super Number>)... is not applicable for the arguments (List<Integer>)
因为我的方法是说:“不要以为你的List可以是任何比Number更具体的东西,我可能会添加各种奇怪的Number到列表中,你只需要处理它,如果你想把它们看作比Number类Object更普遍的东西 – 没关系,我保证它们至less是Number ,但是如果你愿意的话,可以更一般地对待它们。
而extends说,“我不在乎你给我什么样的List ,只要每个元素至less是一个Number ,它可以是任何types的Number ,甚至你自己的奇怪的,定制的,编造的Number只要他们实现了这个接口,我们就很好,我不会在你的列表中添加任何东西,因为我不知道你在那里使用了什么实际的具体types。