通用较低的未绑定与上限有界通配符

时间:2012-10-15 11:08:32

标签: java generics wildcard bounded-wildcard

import java.util.List;
import java.util.ArrayList;

interface Canine {}
class Dog implements Canine {}
public class Collie extends Dog {
    public static void main(String[] args){
        List<Dog> d = new ArrayList<Dog>();
        List<Collie> c = new ArrayList<Collie>();
        d.add(new Collie());
        c.add(new Collie());
        do1(d); do1(c);
        do2(d); do2(c);
    }
    static void do1(List<? extends Dog> d2){
        d2.add(new Collie());
        System.out.print(d2.size());
    }
    static void do2(List<? super Collie> c2){
        c2.add(new Collie());
        System.out.print(c2.size());
    }
}

这个问题的答案告诉我,当一个方法采用通配符泛型类型时,可以访问或修改该集合,但不能同时访问或修改它们。 (凯西和伯特)

当一个方法采用通配符泛型类型时,它是什么意思',可以访问或修改集合,但不能同时访问或修改'

据我所知, 方法do1具有List<? extends Dog> d2,因此d2只能被访问但不能被修改。 方法d2具有List<? super Collie> c2,因此可以访问和修改c2,并且没有编译错误。

Generic guidelines

5 个答案:

答案 0 :(得分:2)

您无法将Cat添加到List<? extends Animal>,因为您不知道该列表是什么类型。那也可能是List<Dog>。因此,您不希望将Cat投入Black Hole。这就是modification List声明这种方式的原因。

同样地,当您从List<? super Animal>中取出某些内容时,您不知道将从中获取什么。您甚至可以获得ObjectAnimal。但是,您可以在此Animal安全地添加List

答案 1 :(得分:1)

我将您的代码粘贴到我的IDE中。在do1

中发出以下错误信号
  

类型List中的方法add(捕获#1-of?extends Dog)不适用于参数(Collie)

当然,这是预期的。

答案 2 :(得分:1)

您无法将Collie添加到List<? extends Dog>,因为此引用可能包含List<Spaniel>

答案 3 :(得分:0)

我将您的代码粘贴到IDEONE http://ideone.com/msMcQ中。它没有为我编译 - 这是我的预期。您确定没有任何编译错误吗?

答案 4 :(得分:0)

  

这个问题的答案告诉我,当一个方法采用通配符泛型类型时,可以访问或修改该集合,但不能同时访问或修改它们。 (凯西和伯特)

这是一个公平的第一近似值,但不太正确。更正确的是:

您只能向Collection<? extends Dog>添加null,因为其add方法的参数为? extends Dog。无论何时调用方法,都必须传递属于声明的参数类型的子类型的参数;但对于参数类型? extends Dog,如果表达式为null,编译器只能确保参数是兼容类型。但是,您当然可以通过调用clear()remove(Object)修改集合。

另一方面,如果从Collection<? super Dog>读取,则其迭代器的返回类型为? super Dog。也就是说,它将返回作为某种未知超类型Dog的子类型的对象。但不同的是,Collection可以是Collection<Object>,仅包含String的实例。因此

for (Dog d : collection) { ... } // does not compile

所以我们唯一知道的是返回Object的实例,即迭代这样一个Collection的唯一类型正确的方法是

for (Object o : collection) { ... }

但是可以从一个集合中读取,你只是不知道你会得到什么类型的对象。

我们可以很容易地将该观察推广到:给定

class G<T> { ... }

G<? extends Something> g;

我们只能将null传递给声明类型为T的方法参数,但是我们可以调用返回类型为T的方法,并为结果分配类型为Something的变量。

另一方面,

G<? super Something> g;

我们可以将任何类型Something的表达式传递给声明类型为T的方法参数,并且我们可以调用返回类型为T的方法,但只将结果赋给变量输入Object

总而言之,对通配符类型使用的限制仅取决于方法声明的形式,而不取决于方法的作用。