Java 如何使编译器不允许对上限引用调用方法

Java 如何使编译器不允许对上限引用调用方法,java,generics,io,Java,Generics,Io,我知道以下语法不合法: void dolist2(List<? extends Number> list) { list.add(new Integer(3)); } 但我不知道编译器如何知道它是不合法的。如果我看一下List.java的源代码,我会看到: 布尔加法 我看不出这个声明有什么特别之处,甚至像@IllegalWhenInvokedOnUpperBoundReference这样的注释也没有。编译器如何知道强制执行此限制?我如何对自己的类设置类似的限制 编译器知道您

我知道以下语法不合法:

void dolist2(List<? extends Number> list) {
    list.add(new Integer(3));
}
但我不知道编译器如何知道它是不合法的。如果我看一下List.java的源代码,我会看到:

布尔加法


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

编译器知道您可以传递列表中任何数字子类型的列表,因为Integer不是的实例?扩展号码?extends Number的意思是:一个未知的类型,它是或extends Number。由于类型未知,编译器无法判断Integer是有效类型,因此拒绝编译

您也不能将字符串添加到列表中,因为编译器知道该字符串不扩展整数。类型检查是编译器的角色之一

您似乎认为这是列表所具有的特殊功能,而您的代码所不能具有的。不是。这只是泛型类型的规则:

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
    }
}
编译失败,因为调用inspect时包含一个字符串:

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

来源:Java教程在Java泛型中,通配符有两种边界:

??延伸

??超级Y

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

第二种形式super告诉您和编译器,该类保证最多接受Y。这些值将乐于接受Y类型的实例,因为它们期望Y本身或Y的超类。。。因此,您始终可以将值写入超级通配符

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

public static <T> void copy(List<? super T> dest, List<? extends T> src) {
  for (T t: src) dest.add(t);
}

您可能知道new Integer3正在将值为3的装箱整数添加到列表中。它没有分配某事物的三个元素。@Bathsheba实际上没有在表达式new Integer3中进行装箱转换。您所做的只是对值进行包装,而不是装箱。要获得装箱,您必须编写整数I=3,以便隐式进行包装。是的,谢谢,这是正确的,我理解其原因。我要问的是,编译器如何看待add方法,并知道add方法不能以这种方式使用,我自己如何使用这种机制code@Mishax. 我不明白。您在自己的代码中使用该机制是什么意思?这是泛型特性。你想要什么样的行为?最好用你的具体代码来解释。@Mishax。您也可以将类设置为泛型。这个特性将适用于您的类。我不认为Add方法是语言特性。我认为它是API和集合框架的一部分。你的评论开始证实我已经有了一种令人沮丧的感觉,即这是硬编码到编译器中的,而这个函数对我来说是不可用的。这很不幸。你能给我举个例子吗?这就是我要寻找的,我如何编写我自己的类和方法,并让编译器阻止对上限引用的调用。嗯。。。整数是数字的一个子类。所以我可以写void dolist1ListYes,但是super和extends并不是一回事。谢谢你们两位的帮助。我很困惑,因为在每一个案例中,我都看到这种行为是在哪里解释的,它们指的是集合的add方法。这可以解释为什么remove方法是removeObject o而不是removee E,而add方法是adde E而不是addObject o。实际上,我可以通过声明编译器不允许调用返回值具有下限类型参数的调用来总结整个讨论吗,不允许调用其中一个形式方法参数具有上限类型参数的调用?当我这样读的时候,它似乎很清楚。@Mishax:你已经发现PECS生产者延伸了消费者超级规则。
Box.java:21: <U>inspect(U) in Box<java.lang.Integer> cannot
  be applied to (java.lang.String)
                        integerBox.inspect("10");
                                  ^
1 error
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
  for (T t: src) dest.add(t);
}