我正在尝试使用Java泛型来完成某些事情,并且由于类型擦除,因为我本能地采用的方法在这种语言中不起作用,所以我有一段时间。但是,如果我得到以下工作,我可以将一些合理的东西拼凑在一起。我有两个班:
class A {}
class B extends A {}
第三节课:
class C<T extends A> {}
如果我给它一个C
或A
的实例,我想要一个返回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 ?
非常感谢!
答案 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
仍必须是TRet
或TRet
的子类。 (或者从另一个方向看,TRet
必须是TArg
或超级TArg
。)
虽然我认为这有点痛苦。在评论中已经提到过,奇异类型的版本在Java 8上编译。
但是这个:
有点让我好奇。看起来你好described an attempted solution but not the actual problem,这让我想知道我们的建议在这里是否真的有用。如果他们是优秀的,但如果他们不是,请不要犹豫,编辑OP或评论澄清。但是,如果我得到以下工作,我可以将一些合理的东西拼凑在一起。