Java 带参数的泛型方法与带通配符的非泛型方法
根据,在某些情况下,泛型方法没有使用通配符类型的等效非泛型方法。根据这个答案, 如果方法签名使用多级通配符类型,则泛型方法签名和通配符版本之间始终存在差异 他们给出了一个方法Java 带参数的泛型方法与带通配符的非泛型方法,java,generics,Java,Generics,根据,在某些情况下,泛型方法没有使用通配符类型的等效非泛型方法。根据这个答案, 如果方法签名使用多级通配符类型,则泛型方法签名和通配符版本之间始终存在差异 他们给出了一个方法voidprint1(List),该方法“需要一个相同类型的框列表。”通配符版本为voidprint2(List>x){ 从直觉上看,这些定义应该是等价的。但是,调用f(ArrayList.class)使用第一种方法编译,而调用g(ArrayList.class)使用第二种方法会导致编译时错误: 测试中的g(java.la
voidprint1(List)
,该方法“需要一个相同类型的框列表。”通配符版本为voidprint2(List>x){
从直觉上看,这些定义应该是等价的。但是,调用f(ArrayList.class)
使用第一种方法编译,而调用g(ArrayList.class)
使用第二种方法会导致编译时错误:
测试中的g(java.lang.Class>)
无法应用于(java.lang.Class)
有趣的是,这两个函数都可以用彼此的参数调用,因为编译如下:
类测试{
猜猜:表示第一个的东西?(ArrayList)没有“实现”ArrayList
(借助于双嵌套通配符)。我知道这听起来很有趣,但是
考虑(对于原始列表):
void g(类x){}//失败
void g(类>x){}
无效d(){
ArrayList d=新的ArrayList();
f(d);
g(d);
}
}
这个
//不在g(d)上编译
公开课考试{
如果类型参数是通配符参数化类型,则不会出现问题:
Class<ArrayList<?>> foo = null;
f(foo);
g(foo);
类
很复杂
我没有仔细阅读语言规范,因此我不确定为什么子类型在显式类型参数情况下有效,但在通配符情况下无效。这也很可能是一个错误。这些不完全相同:
<T extends Iterable<?>> void f(Class<T> x) {}
void g(Class<? extends Iterable<?>> x) {}
,因此它不匹配
更清楚地说,g
将接受Foo实现Iterable
,但不接受arararylist实现Iterable
好吧,按照规范,两种调用都不合法。但是为什么第一种类型检查而第二种类型不检查呢
不同之处在于如何检查方法的适用性(具体请参见)
- 为了使简单、非泛型的
g
适用,参数ClassArrayList
,writedArrayList
任何参数化C
都是原始类型C
的一个(直接)子类型。因此ArrayList
是ArrayList
的一个子类型,但不是相反。从传递的角度看,ArrayList
不是Iterable
的子类型
因此,g
不适用
f
是泛型的,为了简单起见,让我们假设类型参数ArrayList
是显式指定的。要测试f
的适用性,Class,这是真的
同样要使f
适用,类型参数必须是。这不是因为,正如我们上面所示,ArrayList
不是Iterable
的子类型
那么它为什么要编译呢?
这是一个bug。遵循a和JDT编译器明确排除了第一种情况(包含类型参数)。第二种情况仍然被愉快地忽略,因为JDT认为ArrayList
是Iterable
(TypeBinding.isCompatibleWith(TypeBinding)
)的子类型
我不知道为什么javac的行为是相同的,但我假设是出于类似的原因。您会注意到,当将原始ArrayList
分配给Iterable
时,javac也不会发出未经检查的警告。+1对于一个没有答案的泛型问题,“您不能对泛型执行此操作”改变一下。语义上的差异是可以理解的,但是我觉得奇怪的是它没有编译。从g
中删除Iterable
上的通配符确实会编译,原因如下:void g(Classic在第二个示例中,为什么调用f(d)
成功,而调用g(d)
不编译?与问题中描述的框
类进行类比,签名void g(ArrayList>x)
是否表示g()
接受Iterable(或Iterable子类)的ArrayList这可能是不同的类型,而
,其中类
不是一个集合?我不知道,我会假设,出于同样的原因,您的代码没有编译。我使用了ArrayList两次,以确保它不是特定于类的。如果您愿意,可以将其更改为任何参数化类型,例如box。我的观点是参数化类型似乎在嵌套通配符上消失了,类似于@newacct所提到的。您在这里没有意义。ArrayList
实现了Iterable
@PaulBellora正是。ArrayList
没有实现Iterable
。请记住,Iterable
不在就泛型类型而言,Iterable
。你仍然没有什么意义。关于ArrayList
实现Iterable
的一点来自哪里?其次,Iterable
可以从任何ArrayList
@PaulBellora-uhh是的。我的意思是Iterable
(编辑我的答案)但是它仍然坚持认为,ArrayList
不是匹配项,因为就匹配方法签名而言,Iterable
不是Iterable
,t
与类相关,但Iterable
不是-参见我答案的最后一句+1,我一直不清楚为什么g的类文本泛型类是用原始类型而不是通配符类型参数化的。@PaulBellora:有趣的是,这个问题在Scala中不会发生,因为Scala需要m
// Does not compile on g(d)
public class Test{
<T extends Iterable<?>> void f(ArrayList<T> x) {}
void g(ArrayList<? extends Iterable<?>> x) {}
void d(){
ArrayList<ArrayList> d = new ArrayList<ArrayList>();
f(d);
g(d);
}
}
Class<ArrayList<?>> foo = null;
f(foo);
g(foo);
<T extends Iterable<?>> void f(Class<T> x) {}
void g(Class<? extends Iterable<?>> x) {}