Java多个泛型集合参数编译错误

Java multiple generic collection parameters compile error

真奇怪!请先看一下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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(), new ArrayList<C>());
        new TestMain().test1(new ArrayList(), new ArrayList<C>());
    }
}

语句new TestMain().test(new ArrayList(), new ArrayList())出现编译错误:

Bound mismatch: The generic method test(T, T) of type TestMain is not applicable
for the arguments (ArrayList, ArrayList). The inferred type
ArrayList is not a valid substitute for the bounded parameter

然而:

1
2
3
4
5
 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(), new ArrayList<C>()) --> compiled ok

如果在方法名之前定义泛型,则第二个泛型List参数的类型似乎必须与第一个参数的类型相同。但是,如果我们在参数中定义泛型,就没有限制。

它是编译程序的一个特性还是一个缺陷?有关于它的文件吗?


绝对没有bug;您只是误解了泛型中的子类型规则。

因为我们有B extends A

  • BA的一个亚型。
  • instanceof B也是instanceof A

因为Java数组是协变的:

  • B[]A[]的一个亚型。
  • instanceof B[]也是instanceof A[]

然而,Java泛型是不变量的:

当您具有以下泛型方法声明时:

1
public <T extends A> void test(List<T> a, List<T> b)

那么,正如这里明确指出的,对于类型参数的某些捕获转换,AB必须都具有相同的类型List

由于ListList是两种不同的类型,因此不能将它们混用作为test的实际论据。另外,虽然BCA的子类型,但仿制药是不变的,因此ListList都不是List的。

因此,

1
test(new ArrayList(), new ArrayList<C>()); // error!!! doesn't compile!!!

未编译,这是预期的行为。

也见

  • Java教程/泛型
    • 子类型
    • 野猫游戏更有趣
  • jls 10.10数组存储异常和java.lang.ArrayStoreException
    • Java数组子类型是协变的,不是类型化的;泛型是不变的,是。

相关问题

关于泛型类型规则: