【问题标题】:Java generics in type parameter hiding类型参数隐藏中的 Java 泛型
【发布时间】:2012-09-10 07:05:08
【问题描述】:

假设我有一个这样的界面

public interface Foo<Ret, Arg> {
    public Ret doSomething(Arg arg);
}

以及一个只有包可见性的具体实现类。

class FooImpl<Ret, Arg1, Arg2> implements Foo<Ret, Arg>, Bar<Ret, Arg1, Arg2> {
    // This class also implements something else making use of Arg2, so you cannot safely remove it
    // But nothing relating to Arg2 is needed to create a FooImpl
}

(可能发生这种情况的一个例子是在FooImpl 中实现Foo 和Bar 将两个接口声明的方法转发到一个可变参数方法)

现在,假设在同一个包中的某处有一个静态方法,它返回 FooImpl 和 Foo。有人会认为你可以使用return new FooImpl&lt;Ret, Arg1, ?&gt;(...),而实际上你不能(你必须使用具体的虚拟类型Arg2,即return new FooImpl&lt;Ret, Arg1, Object&gt;(...),比如说)。

知道为什么会这样,尤其是Foo 接口和包可见性有效地将FooImpl 隐藏在使用静态方法的任何内容中吗?是不是因为人们仍然可以在一定程度上使用反射来到达需要具体类型的FooImpl 的Bar 部分?

【问题讨论】:

  • 您收到的错误信息是什么?您是为构造函数获取它还是在尝试将其强制转换为返回时?该静态方法的返回签名是什么?

标签: java generics interface wildcard


【解决方案1】:

我认为这与您的特定设计无关。

你不能用通配符实例化类型。

这也行不通:

return new ArrayList<?>();

如果是这样,它会做其他事情吗

return new ArrayList<Object>();

您需要一个具体的类,但这并不意味着您需要在工厂方法签名中显示它:

static <A,B> Foo<A,B> makeFoo(){
    return new FooImpl<A,B, SomeTypeThatNoOneNeedsToSee>();
}

【讨论】:

    【解决方案2】:

    Java 编译器努力做到不聪明。在很多情况下,很明显它不需要某些信息来生成正确的代码,但它仍然会报错。当 Java 被发明时,全世界都看到 C 以草率的态度尝试编译所有东西,无论多么危险或愚蠢。 javac 的目标是确保人们不能 shoot themselves into the foot easily。

    因此,它假定您提到 Arg2 是有原因的 - 如果某些事情没有必要,您肯定不会将其放入代码中。

    解决方案:

    1. 实现Bar时分配​​一个类型:class FooImpl&lt;Ret, Arg1&gt; implements Foo&lt;Ret, Arg&gt;, Bar&lt;Ret, Arg1, Object&gt;
    2. 创建一个BetterFooImpl&lt;Ret, Arg1&gt; extends FooImpl&lt;Ret, Arg1, Object&gt;。这对 API 的使用者隐藏了第三个类型参数。
    3. 尝试去掉Bar的第三个参数
    4. 谨慎使用泛型。这可能令人惊讶,但在某些情况下泛型根本无法正常工作。这通常是因为细微的实现细节导致@SuppressWarning 注释的爆炸式增长。发生这种情况时,我会问 SO,当我找不到我能理解的解决方案时,我会删除泛型。编写可维护的代码比在泛型迷宫中寻找巧妙的方法更重要。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-06-27
      • 2017-10-06
      • 2015-11-28
      • 1970-01-01
      • 1970-01-01
      • 2012-05-29
      • 1970-01-01
      相关资源
      最近更新 更多