传递子类 java_关于java:为什么只在某些地方允许将子类传递给有界通配符?

以下是来自Generics教程的:

假设R类扩展S,

public void addR(List extends S> s) {

s.add(0, new R()); // Compile-time error!

}

您应该能够理解为什么不允许使用上面的代码。s.add()的第二个参数的类型是?扩展s——s的未知子类型。因为我们不知道它是什么类型,所以我们不知道它是否是r的超类型;它可能是或可能不是这样的超类型,所以在那里传递r是不安全的。

我已经读了几遍了,但我还是不太明白为什么下面是一个错误

给出list.add()的签名

void add(int index, E element)

它不等于

void add(int index, extends S> element) // just to explain the idea, not a valid syntax

为什么它是一个错误调用add(0,new r())r是一个s?

以下是斜体文本所指的内容:

List extends S>类型的参数s不仅可以是List或List的实例,而且可以是List的实例,其中T扩展s。在这种情况下,即使R也扩展了s,R也不一定扩展了T(它们可能是,例如类层次中的兄弟姐妹)。由于在这样的集合中只能放置类型为T的值,因此编译器无法保证在编译时将R放置在该集合中是安全的。

为了给出一个更具体的例子,即使Double扩展了Number,也不能将Double添加到List extends Number>中!这是因为类型为List extends Number>的变量可以在运行时被分配一个List,并且不允许在这样的列表中添加Double。

实际上,您不能实际调用声明为List extends S>的列表的add方法,因为在运行时,通配符始终可以表示s的某些子类型,而这些子类型不是您要添加的内容的超类。但是,您可以从这样的列表中读取,因为它保证通配符是s的子类型,因此可以分配给s类型的变量:

public S getElement(List extends S> s) {

S result = s.get(0);

return result;

}

这个一般概念被称为PECS(生产者扩展,消费者超级)。有效Java的第5章(方便地说,它是你可以从书的网站下载的示例性章节)有更多的关于这个和其他微妙的泛型的说法。

等等,T和R是类层次结构中的兄弟,也是S,为什么您只能将T放在这样的集合中,而不能放在R中?感谢链接到有效的Java。

我添加了一个更具体的例子。希望这能有所帮助。

那么如果它包含一个list和一个list呢?它是一个非参数化的异类列表,如JDK1.4之前的列表。GET仍然可以正常工作,因为您正在分配给一个数字类型变量。

+我指对了方向。

菲尔解释得很好!参数类型可以声明为list,但在运行时传递给方法的实际值始终是list、list、list或list。这就是为什么编译器不相信向这个列表中添加一个新的r()是一个好主意。

"你不能真正调用add方法"你可以调用它并传递null。

我想这是最简单的解释

类结构:

public class List extends S> {}

public class S {}

public class R extends S {}

public class T extends R {}

代码用法:

List list = new List();

在这种情况下,以下内容无效:

list.add(new R());

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值