类型参数隐藏中的Java泛型

类型参数隐藏中的Java泛型,java,generics,interface,wildcard,Java,Generics,Interface,Wildcard,假设我有一个这样的接口 public interface Foo<Ret, Arg> { public Ret doSomething(Arg arg); } 公共接口Foo{ 公共再剂量测定法(Arg-Arg); } 以及一个只具有包可见性的具体实现类 class FooImpl<Ret, Arg1, Arg2> implements Foo<Ret, Arg>, Bar<Ret, Arg1, Arg2> { // This

假设我有一个这样的接口

public interface Foo<Ret, Arg> {
    public Ret doSomething(Arg arg);
}
公共接口Foo{
公共再剂量测定法(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{
//此类还利用Arg2实现了其他功能,因此您无法安全地将其删除
//但是创建FooImpl不需要任何与Arg2相关的内容
}
(这可能发生的一个例子是在
FooImpl
中实现
Foo
Bar
,将两个接口声明的方法转发给一个varargs方法)

现在,假设在同一个包中的某个地方有一个静态方法,它将
FooImpl
作为
Foo
返回。有人会认为您可以使用
返回新的FooImpl(…)
,而实际上您不能(您必须使用一个具体的伪类型,如
Arg2
,也就是说,..
返回新的FooImpl(…)


你知道这是为什么吗,尤其是
Foo
接口和包可见性有效地隐藏了
FooImpl
,不让任何使用静态方法的人看到吗?是不是因为人们仍然可以在某种程度上使用反射,以便到达
FooImpl
部分,其中需要具体的类型?

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

您不能用通配符实例化类型

这也行不通:

return new ArrayList<?>();
返回新的ArrayList();
如果它真的这么做了,它还会做别的事情吗

return new ArrayList<Object>();
返回新的ArrayList();
您需要一个具体的类,但这并不意味着您需要在factory方法签名中显示它:

static <A,B> Foo<A,B> makeFoo(){
    return new FooImpl<A,B, SomeTypeThatNoOneNeedsToSee>();
}
静态Foo makeFoo(){
返回新的FooImpl();
}

Java编译器努力做到不聪明。在许多情况下,它显然不需要一些信息来生成正确的代码,但它仍然会抱怨。当Java被发明的时候,全世界都看到了C以草率的态度试图编译所有东西,无论多么危险或愚蠢。
javac
的目标是确保人们不能这样做

因此,它假设您提到
Arg2
,这是有原因的——如果某件事情不需要它,您肯定不会将它放入代码中

解决方案:

  • 在实现
    Bar
    时指定类型:
    class FooImpl实现Foo,Bar
  • 创建一个
    BetterFooImpl扩展FooImpl
    。这对API的使用者隐藏了第三个类型参数
  • 尝试删除
    Bar的第三个参数
  • 小心使用泛型。这可能会令人惊讶,但在某些情况下,泛型根本不能很好地工作。这通常是因为微妙的实现细节导致了
    @SuppressWarning
    注释的激增。当这种情况发生时,我会这样问,当我找不到我能理解的解决方案时,我会删除泛型。编写可维护代码比在泛型迷宫中找到聪明的方法更重要

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