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
子类型的参数。因此,它不再担心类型不匹配。
我试图通过不同的子层次结构路径来展示我的意思。就像家谱一样。
如下所述(我可能解释得不好,请注意):
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
子类型的参数。因此,它不再担心类型不匹配。
我试图通过不同的子层次结构路径来展示我的意思。就像家谱一样。