Java 带扩展名的通配符

Java 带扩展名的通配符,java,generics,wildcard,Java,Generics,Wildcard,代码: 在本例中,我们让编译器在内部创建一个新的匿名类型,该类型标记为CAP#2,这样所有Integer的超类型的唯一实例就是“CAP#2的实例” 问题我现在明白了通配符的工作原理了吗?让我们尝试从java.util.List的不同角度来看待出现的问题 List<? super Integer> ints= new ArrayList<Integer>(); ints.add(new Object());//error 公共接口列表扩展集合{ * * 布尔加法(E);

代码:

在本例中,我们让编译器在内部创建一个新的匿名类型,该类型标记为
CAP#2
,这样所有
Integer的
超类型的唯一实例就是“
CAP#2
的实例”


问题我现在明白了通配符的工作原理了吗?

让我们尝试从java.util.List的不同角度来看待出现的问题

List<? super Integer> ints= new ArrayList<Integer>(); 
ints.add(new Object());//error
公共接口列表扩展集合{
*
*
布尔加法(E);
*
*
}

当您指定
List时,为了本次讨论的目的,让我们忽略Integer是final这一事实

当您将变量的类型设置为
List<?扩展整数>
,编译器不允许调用任何具有泛型类型参数作为方法参数的List方法。这些参数处于所谓的逆变位置,如果编译器允许您执行您试图执行的操作,那么Java的类型系统将比现在更加不健全。编译器只知道列表的元素类型是Integer的某个未知子类型,内部称为CAP#1。现在,尝试调用
add(CAP#1,int)
并将任何内容作为第一个参数将失败。唯一的例外是
null
,这是因为与Java中的任何其他值不同,null是每个引用类型的成员,因此它必须是CAP#1的成员。请注意,编译器将允许您调用
List<>的任何方法?扩展没有泛型类型输入但可能产生泛型类型输出的整数>

与@Maxim Kirilov给出的答案相反,当您将变量类型设置为
List<?超级整数>
,编译器不允许您添加任何超类型的整数。它只知道未知类型是整数的某个超类型,内部称为CAP#2,因此任何整数或任何整数的子类型都可以添加到列表中(因为无论CAP#2是什么,S都是整数的子类型,是CAP#2的子类型,所以
add(CAP#2,int)
将接受第一个参数中的S)

相比之下,您尝试使用一个对象调用该方法,该对象不是Integer的子类型。编译器拒绝传递需要CAP#2的对象的尝试(如上所述)。

我理解编译器无法知道需要哪个特定的整数子类型,因此它不会接受任何类型的整数。编译器所知道的就是列表的元素类型是Integer的某个未知子类型,内部称为CAP#1。现在尝试调用add(CAP#1,int)并将任何内容作为第一个参数都将失败。唯一的例外是null,这是因为与Java中的任何其他值不同,null是每个引用类型的成员,因此它必须是CAP#1的成员。这并不意味着我们不能从
null
int添加任何内容。如果我们说
CAP#1
相当于
null
的匿名类型,那么就可以了。或者我不明白你的意思,对吗?
null
具有所有非基本类型,而不仅仅是
CAP\1
Integer
Map>
;你还没看到这个吗?在Scala中,类型系统将正式名称AnyRef分配给该类型。您不能向CAP#1列表中添加除null以外的任何内容的原因是,无论您传入什么参数,即使是
整数
,编译器都无法确定该类型与
CAP#1
之间的关系。您没有也不能声明任何此类关系,因为该类型是通配符。但是,说
CAP#1
等同于
AnyRef
是错误的。
List<? super Integer> ints= new ArrayList<Integer>(); 
ints.add(new Object());//error
public interface List<E> extends Collection<E> {
    *
    *

    boolean add(E e);

    *
    *
}