Java多个泛型集合参数编译错误
太奇怪了!请先看一下代码:
public class A {}
public class B extends A {}
public class C extends A {}
public class TestMain {
public <T extends A> void test(T a, T b) {}
public <T extends A> void test(List<T> a, List<T> b) {}
public void test1(List<? extends A> a, List<? extends A> b) {}
public static void main(String[] args) {
new TestMain().test(new B(), new C());
new TestMain().test(new ArrayList<C>(), new ArrayList<C>());
new TestMain().test(new ArrayList<B>(), new ArrayList<C>());
new TestMain().test1(new ArrayList<B>(), new ArrayList<C>());
}
}
语句 new TestMain().test(new ArrayList(), new ArrayList
出现编译错误:
绑定不匹配:TestMain 类型的泛型方法 test(T, T) 不适用 对于参数
(ArrayList, ArrayList
。推断类型) 数组列表
不是有界参数的有效替代品
但是:
new TestMain().test(new B(), new C()) --> compiled ok
new TestMain().test(new ArrayList<C>(), new ArrayList<C>()) --> compiled ok
new TestMain().test1(new ArrayList<B>(), new ArrayList<C>()) --> compiled ok
如果我们在方法名称之前定义泛型,那么第二个泛型 List
参数的类型必须与方法名称相同第一的。但如果我们在参数中定义泛型则没有限制。
这是编译程序的一个特性还是一个错误?有一些关于它的文档吗?
So strange! Please have a look the code first:
public class A {}
public class B extends A {}
public class C extends A {}
public class TestMain {
public <T extends A> void test(T a, T b) {}
public <T extends A> void test(List<T> a, List<T> b) {}
public void test1(List<? extends A> a, List<? extends A> b) {}
public static void main(String[] args) {
new TestMain().test(new B(), new C());
new TestMain().test(new ArrayList<C>(), new ArrayList<C>());
new TestMain().test(new ArrayList<B>(), new ArrayList<C>());
new TestMain().test1(new ArrayList<B>(), new ArrayList<C>());
}
}
The statement new TestMain().test(new ArrayList<B>(), new ArrayList<C>())
gets a compilation error:
Bound mismatch: The generic method test(T, T) of type TestMain is not applicable
for the arguments(ArrayList<B>, ArrayList<C>)
. The inferred typeArrayList<? extends A>
is not a valid substitute for the bounded parameter<T extends A>
However:
new TestMain().test(new B(), new C()) --> compiled ok
new TestMain().test(new ArrayList<C>(), new ArrayList<C>()) --> compiled ok
new TestMain().test1(new ArrayList<B>(), new ArrayList<C>()) --> compiled ok
If we define the generic before the method name, it seems the type of the second generic List
parameter must be the same as that of the first. But there is no restriction if we define generic in parameters.
Is it a feature or a bug of the compile program? Is there some documentation about it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
绝对没有bug;您只是误解了泛型中的子类型规则。
由于我们有
B extends A
:B
是A
的子类型,instanceof B
也是一个instanceof A
由于 Java 数组是协变的:
B[]
是A[]
的子类型,instanceof B[]
也是instanceof A[]
但是,Java 泛型是不变的:
List
不是List
的子类型instanceof List
。当您具有以下泛型方法声明时:
那么,正如此处明确指出的,
a
和b
必须具有相同的类型,List
code>,用于类型参数
的一些捕获转换。由于
List
和List
是两种不同的类型,因此不能将它们混合作为test
的实际参数。此外,即使B
和C
是A
的子类型,泛型也是不变的,因此List
都不是List
也不是List
。因此,
无法编译,这是预期的行为。
另请参阅
java.lang.ArrayStoreException
相关问题
关于泛型输入规则:
List; Animals = new ArrayList()
?List
与List
在使用 < code>super 和
extends
:Java 泛型:什么是PECS?
扩展
消费者超级
”super
和extends
之间有什么区别Java泛型
和
?列表<?扩展 Number>
数据结构?(你不能!)关于实际的通用错误:
There is absolutely no bug; you simply misunderstood the subtyping rules in generics.
Since we have
B extends A
:B
is a subtype ofA
instanceof B
is also aninstanceof A
Since Java arrays are covariant:
B[]
is a subtype ofA[]
instanceof B[]
is also aninstanceof A[]
However, Java generics are invariant:
List<B>
is NOT a subtype ofList<A>
instanceof List<B>
is NOT aninstanceof List<A>
.When you have the following generic method declaration:
Then, as it's explicitly stated here,
a
andb
must both have the same type,List<T>
, for some capture conversion of type parameter<T extends A>
.Since
List<B>
andList<C>
are two different types, you can't mix them as actual arguments fortest
. Also, even thoughB
andC
are subtypes ofA
, generics are invariant, so neitherList<B>
norList<C>
is aList<A>
.Thus,
doesn't compile, which is expected behavior.
See also
java.lang.ArrayStoreException
Related questions
On generics typing rules:
List<Animal> animals = new ArrayList<Dog>()
?List
is different fromList<Object>
which is different from aList<?>
On using
super
andextends
:Java Generics: What is PECS?
extends
consumersuper
"super
andextends
in Java Generics<E extends Number>
and<Number>
?List<? extends Number>
data structures? (YOU CAN'T!)On actual generic bugs:
这不是一个错误,只是泛型很复杂。尝试将第二个测试方法更改为:
基本上,在您所得到的内容中,没有类型 T 可以满足您传入的内容,这与第一个方法不同,其中 B 和 C 被视为 A。此行为的实际名称我不太明白,但文献中应该有很多例子。
简而言之,即使 B 是 A 的子级,List 仍然是 A 的子级。不是List的子项。
It's not a bug, it's just that generics are complex. Try changing your second test method to:
Basically in what you've got there is no type T that can satisfy what you're passing in, unlike the first method where B and C are just treated as A. The actual name for this behaviour escapes me but there should be plenty of examples in the literature.
In short, even though B is a child of A, List<B> is not a child of List<A>.