0

我知道以下语法是不合法的:

void dolist2(List<? extends Number> list) {
    list.add(new Integer(3));
}

但我不知道编译器如何知道它是不合法的。如果我查看 List.java 的源代码,我会看到:

boolean add(E e);

我看不出这个声明有什么特别之处,甚至没有像@IllegalWhenInvokedOnUpperBoundReference 这样的注释。编译器如何知道强制执行此限制?我如何对自己的课程设置类似的限制?

4

4 回答 4

3

它知道是因为Integer不是? extends Number. ? extends Number意思是:一个未知类型,它是或扩展了 Number。由于类型未知,编译器无法判断 Integer 是有效类型,因此拒绝编译。

您不能将字符串添加到List<Integer>其中之一,因为编译器知道字符串不会扩展整数。类型检查是编译器的角色之一。

您似乎认为这是 List 具有的特殊之处,而您的代码却没有。它不是。这只是泛型类型的规则:

public class Whatever<T> {
    public void foo(T e) {
    }

    public static void main(String[] args) {
        Whatever<? extends Number> w = new Whatever<Integer>();
        w.foo(new Integer(4)); // won't compile
    }
}
于 2013-08-22T06:59:27.773 回答
2

编译器知道您可以传递 in 的任何子类型的NumberList List<? extends Number>。所以,你可以通过List<Double>,List<Float>任何东西。

现在,由于它无法确定该方法获得哪种类型,如果您将任何内容添加到列表中,则它不是类型安全的,并且会导致堆污染。所以,下面的声明:

list.add(new Integer(3));

不安全。您可能要添加IntegerList<Double>. 由于这些类型不兼容,因此将在运行时失败。所以,编译器给你一个错误。这个概念被称为PECS(Producer Extends Consumer Super)


推荐阅读:

于 2013-08-22T06:58:19.847 回答
2

在 java 泛型中,通配符有两种边界:

  • ? extends Y

  • ? super Y

第一种形式,extends告诉你和编译器,你所拥有的保证是一个子类,Y但你不能保证是什么子类......因此,你总是可以从 an 中读取值,extends因为它们保证可以向下转换为 type Y。您不能写入这样的通配符,因为您无法保证该类型与您传递的类型兼容。

第二种形式,super告诉你和编译器,这个类被保证最多采用一个Y. 这些值将很乐意采用类型的实例,Y因为它们期望Y自身...的超类Y。因此,您始终可以将write值设置为super通配符。

下面是使用两种通配符的代码示例:

public static <T> void copy(List<? super T> dest, List<? extends T> src) {
  for (T t: src) dest.add(t);
}
于 2013-08-22T07:29:10.343 回答
0
public class Box<T> {

    private T t;          

    public void set(T t) {
        this.t = t;
    }

    public T get() {
        return t;
    }

    public <U extends Number> void inspect(U u){
        System.out.println("T: " + t.getClass().getName());
        System.out.println("U: " + u.getClass().getName());
    }

    public static void main(String[] args) {
        Box<Integer> integerBox = new Box<Integer>();
        integerBox.set(new Integer(10));
        integerBox.inspect("some text"); // error: this is still String!
    }
}

编译失败,因为我们对检查的调用包含一个字符串:

Box.java:21: <U>inspect(U) in Box<java.lang.Integer> cannot
  be applied to (java.lang.String)
                        integerBox.inspect("10");
                                  ^
1 error

来源:Java 教程泛型

于 2013-08-22T07:14:27.650 回答