为什么仅在某些地方允许将子类传递给有界通配符? [英] Why is passing a subclass to a bounded wildcard only allowed in certain places?
问题描述
说R类扩展S,
public void addR(List< ;? extends S> s){
s.add(0,new R()); //编译时错误!
}
你应该能够弄清楚为什么上面的代码是不允许的。 s.add()的第二个参数的类型是?扩展S - S的未知子类型。由于我们不知道它是什么类型,我们不知道它是否是R的超类型;它可能或可能不是这样一个超类型,所以在那里传递一个R是不安全的。
我已经读了几次,但仍然我不明白为什么以下是错误的
给定List.add()的签名
< pre $
void add(int index,E element)
isn '它等于
void add(int index,< ;? extends S>元素)//只是为了解释这个想法,而不是有效的语法
为什么它是一个错误call add(0,new R())R作为S?
以下是斜体文字所指的内容:
参数 s
,类型列表<?对于< code>列< S>< / code>或< code>列< R>< / $ c的实例$ c $,而且
List< T>
其中 T
扩展 S
。在这种情况下,即使 R
也延伸 S
, R
不一定要扩展 T
(它们可以是,例如类层次中的同胞)。由于您只能在这样的集合中放入 T
类型的值,编译器无法保证在编译时将 R
会有安全的。
举一个更具体的例子,你不能添加 Double
到列表< ;?扩展Number>
,即使 Double 扩展
Number
!这是因为 List <?>类型的变量例如,可以在运行时分配一个
List< Integer>
,然后添加一个 Double
这样的列表是不允许的。
实际上,您实际上不能调用添加
声明为 List的列表的方法<?扩展S>
,因为在运行时,通配符总是可以代表 S
的某个子类型,它不是您想要添加的事物的超类。但是,您可以从这样的列表中读取,因为它保证通配符是 S
的子类型,因此可以分配给变量类型 S
:
public S getElement(List< ;? extends S> s){
S result = s.get(0);
返回结果;
$ / code>
这个总体思想被称为PECS(producer-extends,consumer-super )。 高效的Java 的第5章(很方便,这是您可以从这本书的网站)对泛型的这个和其他微妙之处有更多的话要说。
This following is from generics tutorials:
Say class R extends S,
public void addR(List<? extends S> s) {
s.add(0, new R()); // Compile-time error!
}
You should be able to figure out why the code above is disallowed. The type of the second parameter to s.add() is ? extends S -- an unknown subtype of S. Since we don't know what type it is, we don't know if it is a supertype of R; it might or might not be such a supertype, so it isn't safe to pass a R there.
I have read it a few times but still I don't quite understand why the following is an error
Given the List.add()'s signature
void add(int index, E element)
isn't it equivalent to
void add(int index, <? extends S> element) // just to explain the idea, not a valid syntax
why is it an error call add(0, new R()) R being an S?
Here's what the text in italics is referring to:
The parameter s
, of type List<? extends S>
, could be not just an instance of List<S>
or List<R>
, but also List<T>
where T
extends S
. In that case, even if R
also extends S
, R
does not necessarily extend T
(they could be, e.g. siblings in the class hierarchy). Since you can only put a value of type T
in such a collection, the compiler can't guarantee at compile time that putting an R
there would be safe.
To give a more concrete example, you can't add a Double
to a List<? extends Number>
, even though Double
extends Number
! That's because a variable of type List<? extends Number>
could, for example, be assigned a List<Integer>
at runtime, and adding a Double
to such a list is not allowed.
In fact, you can't actually call the add
method of a list declared to be List<? extends S>
, because at runtime the wildcard could always represent some subtype of S
that isn't a superclass of the thing you want to add. You can however read from such a list, since it's guaranteed that the wildcard is a subtype of S
, and therefore can be assigned to a variable of type S
:
public S getElement(List<? extends S> s) {
S result = s.get(0);
return result;
}
This general idea is referred to as PECS (producer-extends, consumer-super). Chapter 5 of Effective Java (conveniently enough, it's the sample chapter you can download from the book's website) has more to say about this and other subtleties of generics.
这篇关于为什么仅在某些地方允许将子类传递给有界通配符?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!