我有这样的方法:
protected <T> void addThing(T obj) {
process(new Blah<T>(obj));
}
调用它的代码不知道它正在调用addThing()的东西的确切具体类:
Animal f = new Giraffe();
addThing(f);
所以我最终得到的是Blah<Animal>
。但我真正想要的是Blah<Giraffe>
。这可能吗?到目前为止,我能得到的唯一解决方案有点尴尬。我最终将数据对象作为对象引入Blah并根据模板向下转发:
Blah(Object obj) {
// Undesirable downcast.
this.thing = (T)obj;
}
protected <T> void addThing(Class<T> clazz, Object obj) {
process(new Blah<T>(obj));
}
Animal f = new Giraffe();
addThing(f.getClass(), f);
我想我不得不在某个地方做一个可能不安全的堕落,因为我不知道这个子类型?
答案 0 :(得分:2)
与之交互的代码 Blah利用T类来做 一些反思。它需要一个具体的T 而不是一些父类。 - evilfred
不,代码在运行时无法与T交互,因为它永远不会知道T是什么。泛型仅在编译时相关。在将Java代码编译成字节代码之前,会对预处理进行预处理。字节代码对泛型一无所知。
在:
protected <T> void addThing(T obj) {
process(new Blah<T>(obj));
}
Blah [Animal]在编译时被修复,你无法将进程方法的签名转换为Blah [Giraffe]。不是一种选择。
代码在运行时处理的是Blah [Animal],而不是T(或Blah&lt; T&gt;)。永远。什么是你用新Blah创建的子类型&lt; T>是,字节码将其视为Blah [Animal]。您无法在运行时创建新类型。
您对解决方案的想法:
Blah(Object obj) {
// Undesirable downcast.
this.thing = (T)obj;
}
不会起作用,因为T将在编译时解析。
现在,如果您想创建Blah [Giraffe],请不要将新Blah的创建委托给addThing方法。做这样的事情:
private class Blah<T> { }
private class Giraffe { }
public Test_1() {
Blah<Giraffe> f = new Blah<Giraffe>();
addThing2(f);
}
public <T> void addThing2(Blah<T> obj) {
process(obj);
}
public void process(Blah<?> obj) { }
如果你无法修改addThing,那么你可能不需要担心在运行时创建一个带有未知子类型的泛型(因为它在Java中是不可能的) 。您的问题实际上是/无问题(至少对于流程方法而言)。
答案 1 :(得分:1)
我认为构造函数中也允许使用泛型参数类型吗?
class B<T> {
private T thing;
// I thought one could do generic parameter types in constructors as well?
public B(T thing) { this.thing = thing; }
}
class C {
public void whatever() {
Animal f = new Giraffe();
addThing(f);
}
protected <K> void addThing(K object) {
// if you need reflection, object.getClass() will be the K type at run time.
process(new B<K>(object));
}
// process method elided
}