构造具有未知子类型的Java泛型

时间:2011-04-19 22:41:59

标签: java generics

我有这样的方法:

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);

我想我不得不在某个地方做一个可能不安全的堕落,因为我不知道这个子类型?

2 个答案:

答案 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
}