【问题标题】:How do I pass the "T" argument to as a method parameter using Java generics?如何使用 Java 泛型将“T”参数作为方法参数传递?
【发布时间】:2014-04-28 17:20:29
【问题描述】:

我正在使用 JBoss 7.1.3 和 Java 6。我无法弄清楚我需要用什么来代替“???”在下面的代码中让我的方法正常工作。我想要的是实例化我的“T”类的一个实例,每次实例化该类时调用泛型构造函数。下面是方法……

public class MyClass<T extends AbstractModel>
{

    public void myMethod()
    {
        …
        final HashMap<String, String> data = new HashMap<String, String>();
        final T item = getInstance(???, data);

    }


    private T getInstance(final Class<T> class1,
                  final HashMap<String, String> data)
    {
        T retObj = null;
        try
        {
            Constructor ct = class1.getDeclaredConstructor(HashMap.class);
            Object[] argList = new Object[1];
            argList[0] = data;
            retObj = (T) ct.newInstance(argList);
        } catch (Exception e)
        {
        }   // try
        return retObj;
    }   // getInstance

这是我的抽象模型类的构造函数……

public abstract class AbstractDIDOModel 
{

    protected HashMap<String, String> data;

    AbstractModel(final HashMap<String, String> data) 
    { 
        this.data = data;
    }

【问题讨论】:

  • 您只需将class1 传递给MyMethod
  • 是的,但是怎么做?这就是我的问题的要点。如果您知道,请随时回答,我会接受。
  • 被调用的MyMethod 必须知道为class1 传递什么。您必须明白,这没有简单的答案,因为 Java 实际上并没有将T 表示的类型存储在任何地方——您必须自己跟踪。

标签: java generics instantiation


【解决方案1】:

MyClass 应该传入 Class&lt;T&gt;

public class MyClass<T extends AbstractModel>
{
    private final Class<T> type;

    public MyClass(Class<T> type) { this.type = type; }

    public void myMethod()
    {
        …
        final HashMap<String, String> data = new HashMap<String, String>();
        final T item = getInstance(type, data);

    }

由于Type Erasure,在运行时不存在T的信息,因此大多数情况下无法获取它所引用的类型。

还要注意Constructor 是输入的,所以你可以替换它:

Constructor ct = class1.getDeclaredConstructor(HashMap.class);
//...
retObj = (T) ct.newInstance(argList);

有了这个:

Constructor<T> ct = class1.getDeclaredConstructor(HashMap.class);
//...
retObj = ct.newInstance(argList);

如果您的目标是将Class&lt;T&gt; 用作工厂,那么我会采取不同的方法。我只接受Factory&lt;T&gt;,其中Factory&lt;T&gt; 是一个接口:

public interface Factory<T extends AbstractModel> {
   T create(HashMap<String, String> data);
}

然后MyClass&lt;T&gt; 的创建者可以简单地实现这一点,而无需求助于反射:

Factory<ConcreteModel> factory = new Factory<ConcreteModel>() {
   @Override
   public ConcreteModel create(HashMap<String, String> data) {
        return new ConcreteModel(data);
   }
}

【讨论】:

  • “MyClass”类是@Autowired 使用 Spring (3.1.4.RELEASE) 所以我不容易有办法做你建议的这个工厂的事情。还有几十个这样的类,所以有很多代码更改。如果我不能让更短的实现工作,我会试一试。
【解决方案2】:

如果您的类设置了类型参数,您可以使用一个技巧,因为在这种情况下,类型信息在运行时可用。您可以捕获它并将其存储在成员字段中。然后,您可以将该字段用作通用构造方法中的类。

public abstract class AbstractDIDOModel<T> 
{

 private Class<?> persistentClass = (Class<?>) ((ParameterizedType)  this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];

 private T getInstance(final HashMap<String, String> data)
    {
        T retObj = null;
        try
        {
            Constructor ct = persistentClass.getDeclaredConstructor(HashMap.class);
            Object[] argList = new Object[1];
            argList[0] = data;
            retObj = (T) ct.newInstance(argList);
        } catch (Exception e)
        {
        }   // try
        return retObj;
    }

最后,声明你的具体类:

public class MyClass<T extends AbstractModel>
{
   ....
}

【讨论】:

  • 如何调用您在“myMethod”中定义的“getInstance”方法?请注意,它不是 AbstractModel 类的一部分。
  • 你能解释更多吗?
  • 这很酷——我能够参数化包含“myMethod”的类,而不是参数化模型,这最终需要创建模型。所以这个技巧解决了我的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-08
  • 1970-01-01
  • 2016-04-25
  • 2020-05-24
相关资源
最近更新 更多