Java 编译器无法推断通用链上的类型

Java compiler not able to infer type on generic chain

如下所述(我可能解释得不好,请注意):

I want to understand the principle behind this issue so that I can apply that knowledge to the real problem.


问题开始

我在一个旨在成为供许多子系统使用的抽象库的系统中工作。这个想法是要有一个标准的行为可以通过实现来扩展。 我的问题是 java 编译器无法推断方法参数类型,即使它没有任何意义,因为在每个相关泛型 class/method.

上都很好地设置了边界

下面有一个示例,是重现问题的最小示例。我知道这个例子看起来有点傻,但那是因为简化了:

    public class Test {
    public static void main(String[] args) {
        Gen<? extends Base> gen = new HijaGen();
        gen.applyTo(Hija.EXAMPLE);
    }
    private interface Base {
        String getName();
    }
    private enum Hija implements Base {
        EXAMPLE;
        @Override
        public String getName() {
            return this.name();
        }
    }
    private interface Gen<T extends Base> {
        boolean applyTo(T base);
    }
    private static class HijaGen implements Gen<Hija> {
        @Override
        public boolean applyTo(Hija base) {
            return false;
        }
    }
}

基本上它说 applyTo 需要 Base 的子类,而 Hija 是无效的,在我看来这没有意义。

提前致谢。

编辑:

此代码用于库,因此解决方案无法指定类型,此后无法通过特定实现对其进行扩展。

我已经知道,如果我指定泛型类型而不是抛出类型通配符,它​​将完美地工作。但我的问题是,即使 Hija 是 Base 的子类,而且方法 firm 需要 Base 的子类,但它永远不会编译,这怎么可能...

我想了解这个问题背后的原理,以便将这些知识应用到实际问题中。

A Gen<? extends Base> 某物 Gen,它扩展了 Base。它适用于 某些 特定类型的 Base 但我们不知道是哪一种。实际上,这意味着您将永远无法对类型为 Gen<? extends Base> 的变量调用 applyTo,除非传递 null.

将代码更改为

Gen<Hija> gen = new HijaGen();
gen.applyTo(Hija.EXAMPLE);

我怀疑你可能会说你不能那样做,因为你的代码只是一个例子,上面的代码在实际代码中是不可能的。在这种情况下你需要举一个更好的例子

我认为文档 here 中解释了类似的问题,他们提出的问题是制作一个帮助器(或包装器)来阐明类型。所以我想你可以尝试添加这个功能:

private static <T extends Base> boolean applyTo(Gen<T> gen, T base){
    return gen.applyTo(base);
}

并修改主函数如下:

public static void main(String[] args) {
    boolean b = applyTo(new HijaGen(), Hija.EXAMPLE);
}

根据 Carlos 提到的内容,还有另一种方法可以解决此问题。如果您确定Gen<T>.

实施的供应商,则可以使用它

在这里,我们定义了一个工厂方法来创建 Gen 实现的实例并将其转换为 Gen<Base>,这在我看来是对于所有实际用途都是安全的。请注意,工厂方法 get() 不必是静态的。其余代码与您的示例保持不变。

public static void main( String[] args ){
    Gen<Base> gen = (Gen<Base>) get();
    gen.applyTo( Hija.EXAMPLE );
}

static Gen<? extends Base> get(){
    /* Create the instance of the Gen interface implementation here. */
    return new HijaGen();
}

说明

Gen<? extends Base> 期望引用 Gen 的实现实例,该实例使用的类型是 Base 或其子类型。 由于 "sub-type" 可以来自 Base 的许多可能层次结构之一 向下(如下图所示),因此无法确定传递给的参数applyTo() 方法具有相同的子层次结构路径,而不仅仅是具有相同祖先父 Base 的 'relative'。这就是为什么它不允许调用 applyTo(),其引用为 Gen<? extends Base>,参数为 Base

然而,当引用为 Gen<Base> 时,它知道 applyTo() 将接受任何属于 Base 子类型的参数。因此,它不再担心类型不匹配。

我试图通过不同的子层次结构路径来展示我的意思。就像家谱一样。