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

发布于 2024-09-02 15:20:20 字数 1461 浏览 2 评论 0原文

太奇怪了!请先看一下代码:

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 type
ArrayList<? 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

长伴 2024-09-09 15:20:20

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

由于我们有 B extends A

  • BA 的子类型,
  • instanceof B 也是一个 instanceof A

由于 Java 数组是协变的:

  • B[]A[] 的子类型,
  • instanceof B[] 也是 instanceof A[]

但是,Java 泛型是不变的:

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

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

那么,正如此处明确指出的,ab 必须具有相同的类型,List code>,用于类型参数的一些捕获转换。

由于 ListList 是两种不同的类型,因此不能将它们混合作为 test 的实际参数。此外,即使 BCA 的子类型,泛型也是不变的,因此 List 都不是List 也不是 List

因此,

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

无法编译,这是预期的行为。

另请参阅

相关问题

关于泛型输入规则:

在使用 < code>super 和 extends

关于实际的通用错误:

There is absolutely no bug; you simply misunderstood the subtyping rules in generics.

Since we have B extends A:

  • B is a subtype of A
  • an instanceof B is also an instanceof A

Since Java arrays are covariant:

  • B[] is a subtype of A[]
  • an instanceof B[] is also an instanceof A[]

However, Java generics are invariant:

  • List<B> is NOT a subtype of List<A>
  • a instanceof List<B> is NOT an instanceof List<A>.

When you have the following generic method declaration:

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

Then, as it's explicitly stated here, a and b must both have the same type, List<T>, for some capture conversion of type parameter <T extends A>.

Since List<B> and List<C> are two different types, you can't mix them as actual arguments for test. Also, even though B and C are subtypes of A, generics are invariant, so neither List<B> nor List<C> is a List<A>.

Thus,

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

doesn't compile, which is expected behavior.

See also

Related questions

On generics typing rules:

On using super and extends:

On actual generic bugs:

囚你心 2024-09-09 15:20:20

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

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

基本上,在您所得到的内容中,没有类型 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:

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

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>.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文