为什么不允许使用泛型和通配符?

时间:2012-09-06 13:52:55

标签: java generics wildcard super

此代码

static void writeTo(List<? super Apple> apples) {
        apples.add(new Apple());
        apples.add(new Jonathan());
    }

此代码的作者声明

  

参数apples是某种类型的List,它是Apple的基本类型;因此,您知道添加Apple或Apple的子类型是安全的。由于下限是Apple,

Jonathan是Apple的子类。

但是当我尝试这个时

    List<Jonathan> loj = new ArrayList<Jonathan>();
    listSuper(loj);

它给了我这个错误

The method listSuper(List<? super Apple>) in the type Basket<T> is not applicable for the arguments (List<Jonathan>)

listSuper看起来像这样

static void listSuper (List<? super Apple> cont) {}

两者有何不同?

还有什么让我对我发布的第一个代码感到困惑 我想 ? super T意味着T的任何基类型,但从它的外观来看,他添加了T的子类型。我很困惑。

5 个答案:

答案 0 :(得分:5)

List<? super Apple>表示List您可以添加Apple(并且Jonathan Apple,您可以将Jonathan放入该类型的List中。

它可以是List<Apple>List<Fruit>List<Object>,但不能List<Jonathan>,因为您无法将AppleList<Jonathan>放入?。如您所见,在这种情况下,Apple可以是List<? extends Apple>或其任何超类。

List表示Apple您可以获得List<Apple>。它可以是List<Jonathan>List<Fruit>,但不能是List<Fruit>,因为Apple不能保证仅包含extends

此解释称为“producer - super,consumer - super”规则:如果参数充当元素的使用者,则应使用{{1}}声明,反之亦然

答案 1 :(得分:4)

JonathanApple的子类型,而不是超类型。它匹配<? extends Apple>但不匹配<? super Apple>

答案 2 :(得分:0)

代码的作者错了。你不能将Apple的子类传递给一个方法吗?超级苹果,只有苹果本身和超级苹果。如果你想能够添加Apple的子类,你需要使用?延伸Apple。

答案 3 :(得分:0)

type参数必须是Apple的超类型,而不是子类,这是Jonathan。所以,例如,这是有效的:

List<Fruit> loj = new ArrayList<Fruit>();     
listSuper(loj); 

答案 4 :(得分:0)

  

两者有何不同?

     

另外,我发布的第一个代码让我感到困惑的是我   想?超级T意味着任何基本类型的T.但从外观上看   它添加了T的子类型。我很困惑。

您必须区分(1)您可以插入到通用列表中的内容和(2)可以作为参数发送到具有泛型列表参数的方法的内容。

  1. 您可以将Apple的子类型插入apples,因为绑定的类型参数是一个能够引用其所有子类型的基类。

  2. 如果Jonathan不是Apple的超级类型,那么尝试向该方法发送Jonathan列表通常是不正确的,因为我会允许将Apple插入Jonathan列表中。然后,您将获得类型Jonathan的引用,访问它不知道的对象的属性和方法,这不是类型安全的。