javac中java自类型递归类型参数和继承错误

标签 java generics javac java-7 java-6

为什么这段代码不能编译?

public class x
{
    private void test()
    {
        handle(new ThingA());
        handle(new ModifiedThingA());
    }

    private <T extends BaseThing<T>, X extends T> java.util.List<T> handle(X object)
    {
        return object.getList();
    }

    private static class BaseThing<T extends BaseThing<T>>
    {
        public java.util.List<T> getList()
        {
            return null;
        }
    }

    private static class ThingA
        extends BaseThing<ThingA>
    {
    }

    private static class ModifiedThingA
        extends ThingA
    {
    }
}

Java 6 在 handle(new ModifiedThingA()); 中给出了这个错误:

x.java:6: <T,X>handle(X) in x cannot be applied to (x.ModifiedThingA)
            handle(new ModifiedThingA());
            ^

Java 7 甚至不喜欢 handle(new ThingA()); ,这是 Java 7 的输出:

x.java:5: error: invalid inferred types for T; inferred type does not conform to declared bound(s)
            handle(new ThingA());
                  ^
    inferred: ThingA
    bound(s): CAP#1
  where T,X are type-variables:
    T extends BaseThing<T> declared in method <T,X>handle(X)
    X extends T declared in method <T,X>handle(X)
  where CAP#1 is a fresh type-variable:
    CAP#1 extends BaseThing<CAP#1> from capture of ?
x.java:6: error: invalid inferred types for T; inferred type does not conform to declared bound(s)
            handle(new ModifiedThingA());
                  ^
    inferred: ModifiedThingA
    bound(s): CAP#1
  where T,X are type-variables:
    T extends BaseThing<T> declared in method <T,X>handle(X)
    X extends T declared in method <T,X>handle(X)
  where CAP#1 is a fresh type-variable:
    CAP#1 extends BaseThing<CAP#1> from capture of ?
2 errors

在我看来javac误会了ModifiedThingA对于 BaseThing<ModifiedThingA>当它实际上是一个 BaseThing<ThingA> .这是我的错误还是javac的?

最佳答案

javac的行为似乎是正确的。理论上一种类型变量,T , 就足够了。但是,您引入了第二个类型变量 X , 以帮助进行类型推断。 X 的参数首先进行推断,然后根据调用上下文推断 T 的参数推断:

List<ThingA> a = handle(new ThingA());
List<ThingA> b = handle(new ModifiedThingA());

但是,您的调用上下文不会对返回类型设置任何界限。因此编译器是 forced引入一个类型变量( CAP#1 ),其下限为 null 类型。 T的参数将被推断为 glb(BaseThing<CAP#1>) = BaseThing<CAP#1> .鉴于其下限,X不能证明是 T 的子类型.

有两种或三种方法。

  1. 手动推断(如果很少需要,可以)
  2. 提供一个返回类型为 void 的“重载”(急需另一个名字)
  3. 如果返回的列表是不可变的或防御性副本,您可以断开类型参数 T从它的边界参数

我更喜欢选项 3:

private <T extends BaseThing<T>> List<T> handle(BaseThing<? extends T> object) {
    return new ArrayList<T>(object.getList());
    // or (using guava's ImmutableList)
    return ImmutableList.copyOf(object.getList());
}

快乐的泛型。

关于javac中java自类型递归类型参数和继承错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12058384/

相关文章:

java - 彼此有 2 个本地事务(在不同的数据源上)

java - jasperreports 图像总是模糊的

scala - 无法在 Scala 中编写同时适用于 Double 和 Float 的方法

java - 从通用抽象类java返回子类

c++ - 需要 C++ 中非常通用的 argmax 函数

包的 javac 编译问题

java - Apache ant javah 任务不适用于 jdk 10+

java - 当 EditText 输入为空时 Android 应用程序崩溃

java - 使用 Jersey 2 客户端发布空 body

java - 当没有这样的类时,如何使用 ant/javac 编译 "import pack.*"?