Java Generics:返回泛型类的对象,其类型参数是参数T的超级

时间:2014-04-17 16:13:14

标签: java generics

我正在尝试使用Java泛型来完成某些事情,并且由于类型擦除,因为我本能地采用的方法在这种语言中不起作用,所以我有一段时间。但是,如果我得到以下工作,我可以将一些合理的东西拼凑在一起。我有两个班:

class A {}

class B extends A {}

第三节课:

class C<T extends A> {}

如果我给它一个CA的实例,我想要一个返回B实例的通用工厂方法。第一次尝试可能如下所示:

<T extends A> C<T> getObject(T t) { ... }

我认为我遇到的问题不是很独特,最容易通过以下方式解释:

B b = new B();
C<A> = getObject(b);

我定义了getObject的方式,上面的调用将返回C<B>类型的对象,该对象不是C<A>并且不从C<A>继承,因此不会编译。

我想知道的是:是否可以调用一些泛型魔法,以便编译器选择T中的泛型类型getObject作为上述函数调用中涉及的超类,即A ?

非常感谢!

2 个答案:

答案 0 :(得分:1)

我要继续“窃取答案”(见问题评论:))。

您的班级定义没有任何问题。有时你只需要给编译器一个提示,以便在调用泛型方法时帮助它进行类型推断(猜测它应该替换的类型而不是泛型参数):

public class Test {

    static class A { }
    static class B extends A { }
    static class C<T extends A> { }

    public static <T extends A> C<T> getObject(T obj) {
        return null; // We don't need to construct anything here
    }

    public static void main(String[] args) {
        // This compiles just fine
        C<A> result1 = Test.<A>getObject(new B());
        // Of course you can just type-cast the argument
        C<A> result2 = Test.getObject((A) new B());
    }

}

UPDATE (再次,Sotirios的信用)Java 8显然有一个改进的泛型类型推断,你的代码可以在没有如上所示的显式参数规范的情况下工作(即C<A> result = getObject(new B());只会工作开箱即用)。

答案 1 :(得分:1)

您可以做的一件事就是将声明更改为:

// (I've deviated from Java generic naming convention for clarity)
<TRet extends A, TArg extends TRet> C<TRet> getObject(TArg arg) { ... }

所以现在返回类型和参数类型是独立推断的:

  • TRet是根据返回值的赋值类型推断的。
  • 根据参数的类型推断出
  • TArg

TArg仍必须是TRetTRet的子类。 (或者从另一个方向看,TRet必须是TArg或超级TArg。)

虽然我认为这有点痛苦。在评论中已经提到过,奇异类型的版本在Java 8上编译。

但是这个:

  

但是,如果我得到以下工作,我可以将一些合理的东西拼凑在一起。

有点让我好奇。看起来你好described an attempted solution but not the actual problem,这让我想知道我们的建议在这里是否真的有用。如果他们是优秀的,但如果他们不是,请不要犹豫,编辑OP或评论澄清。