太奇怪了!请先查看代码:
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<B>(), new ArrayList<C>())
收到编译错误:
绑定不匹配:TestMain类型的通用方法测试(T,T)不适用 对于参数
(ArrayList<B>, ArrayList<C>)
。推断类型ArrayList<? extends A>
不是有界参数的有效替代<T extends A>
然而:
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
参数的类型似乎必须与第一个通用{{1}}参数的类型相同。但是如果我们在参数中定义泛型则没有限制。
它是编译程序的功能还是错误?有没有关于它的文件?
答案 0 :(得分:18)
绝对没有错误;你只是误解了泛型中的子类型规则。
因为我们有B extends A
:
B
是A
instanceof B
也是instanceof A
由于Java数组是协变的:
B[]
是A[]
instanceof B[]
也是instanceof A[]
然而,Java泛型是不变的:
List<B>
不是List<A>
instanceof List<B>
不是instanceof List<A>
。如果您有以下通用方法声明:
public <T extends A> void test(List<T> a, List<T> b)
然后,正如此处明确说明的那样,对于类型参数a
的某些捕获转换,b
和List<T>
必须具有相同的类型<T extends A>
。
由于List<B>
和List<C>
是两种不同的类型,因此您不能将它们作为test
的实际参数混合使用。此外,即使B
和C
是A
的子类型,泛型也是不变的,因此List<B>
和List<C>
都不是List<A>
。< / p>
因此,
test(new ArrayList<B>(), new ArrayList<C>()); // error!!! doesn't compile!!!
不编译,这是预期的行为。
java.lang.ArrayStoreException
关于泛型类型规则:
List<Animal> animals = new ArrayList<Dog>()
? List
与List<Object>
的区别与List<?>
不同使用super
和extends
:
Java Generics: What is PECS?
extends
consumer super
”super
and extends
in Java Generics <E extends Number>
and <Number>
? List<? extends Number>
data structures?(你不能!)关于实际的通用错误:
答案 1 :(得分:9)
这不是一个错误,只是仿制药很复杂。尝试将第二种测试方法更改为:
public <T extends A, K extends A> void test(List<T> a, List<K> b) {
基本上在你所拥有的东西中没有类型T可以满足你传入的东西,不像第一种方法,其中B和C只是被视为A.这种行为的实际名称逃脱了我但是应该在文献中有很多例子。
简而言之,即使B是A的孩子,List&lt; B&gt;不是List&lt; A&gt;的孩子。