为什么仅在某些地方允许将子类传递给有界通配符? [英] Why is passing a subclass to a bounded wildcard only allowed in certain places?

查看:83
本文介绍了为什么仅在某些地方允许将子类传递给有界通配符?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是来自泛型教程:

说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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆