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

Gel*_*ang 8 java generics collections compiler-errors

这么奇怪!请先查看代码:

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>());
    }
}
Run Code Online (Sandbox Code Playgroud)

该语句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
Run Code Online (Sandbox Code Playgroud)

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

它是编译程序的功能还是错误?有关于它的一些文件吗?

pol*_*nts 18

绝对没有错误; 你只是误解了泛型中的子类型规则.

既然我们有B extends A:

  • B 是一个子类型 A
  • 一个instanceof B也是一个instanceof A

由于Java数组是协变的:

  • B[] 是一个子类型 A[]
  • 一个instanceof B[]也是一个instanceof A[]

但是,Java泛型是不变的:

  • List<B> 不是的子类型 List<A>
  • a instanceof List<B>不是instanceof List<A>.

当您具有以下通用方法声明时:

public <T extends A> void test(List<T> a, List<T> b) 
Run Code Online (Sandbox Code Playgroud)

然后,正如此处明确说明的那样,a并且b必须两者具有相同的类型List<T>,对于某些类型参数的捕获转换<T extends A>.

由于List<B>List<C>是两种不同的类型,您不能将它们作为实际参数混合使用test.而且,即使B并且C是亚型A,泛型也是不变的,所以既不是List<B>也不List<C>List<A>.

从而,

test(new ArrayList<B>(), new ArrayList<C>()); // error!!! doesn't compile!!!
Run Code Online (Sandbox Code Playgroud)

不编译,这是预期的行为.

也可以看看

相关问题

关于泛型类型规则:

使用superextends:

关于实际的通用错误:

  • 当然,感谢共同和反对,感谢PGL. (3认同)

Cur*_*Dog 9

这不是一个错误,只是泛型是复杂的.尝试将第二种测试方法更改为:

    public <T extends A, K extends A> void test(List<T> a, List<K> b) {
Run Code Online (Sandbox Code Playgroud)

基本上在你所拥有的东西中没有类型T可以满足你传入的东西,不像第一种方法,其中B和C只是被视为A.这种行为的实际名称逃脱了我但是应该有很多文献中的例子.

简而言之,即使B是A的孩子,List <B>也不是List <A>的孩子.


归档时间:

查看次数:

2630 次

最近记录:

12 年,1 月 前