Java Generics - 获取类的实例

时间:2014-03-21 14:42:57

标签: java generics

我有一个名为Data的抽象类,带有一个getInstance()方法,该方法应该返回Data的具体子类的实例。

我想将一个String传递给getInstance方法,这个字符串将准确定义将返回的类。

到目前为止,我有:

public abstract class Data {

  private Map<String, Data> instances;

  public <T extends Data> T  getInstance(Class<T> type, String dataName) {
    return type.cast(instances.get(dataName)); 
  }

}

getInstance()方法在instances映射中查找正确的实例。我认为如果填充地图(由Spring填充),这应该没问题,但调用者必须将Class<T> type参数与String dataName参数匹配。

我有什么方法可以删除Class<T> type参数而没有泛型警告?

2 个答案:

答案 0 :(得分:2)

不,如果您在不知道类型的运行时类的情况下尝试强制转换为泛型类型,则会始终收到警告。不,没有办法获得泛型类的实例而不将其作为参数提供 - 泛型会在运行时被删除。

没有显式强制转换就没有警告的唯一方法是返回Object或Data(取决于你的Map)并要求用户改为使用:

public Data getInstance(String dataName) {
    return instances.get(dataName); 
}
// OR
public Object getInstance(String dataName) {
    return instances.get(dataName); 
}

在我看来,最好提供两种方便的方法:Data getInstance(String)<T extends Data> T getInstance(Class<T>, String)。这基本上也是OSGI在BundleContext类中所做的事情,因此可以获得服务引用,区别在于,不可能获得具有任意id的服务(id始终是类的名称) ):

ServiceReference<?> BundleContext#getServiceReference(java.lang.String clazz) 
ServiceReference<S> BundleContext#getServiceReference(java.lang.Class<S> clazz) 

答案 1 :(得分:1)

您可以完全跳过class参数。

public <T extends Data> T getInstance(String dataName) {
    return (T)instances.get(dataName);
}

这仍会产生警告(您可以抑制)。如果映射中的实际类与预期类型不同,则两种方式都将抛出运行时异常。在我的示例中,编译类型推理在某些情况下不起作用,您需要在调用时指定类型:Data.<SubClass>getInstance("name");

如果密钥数据的子类型不正确,可以使用一个解决方案,返回null。

public <T extends Data> T getInstance(Class<T> clazz, String dataName) {
    Data d = instances.get(dataName);
    if (d != null && clazz.isAssignableFrom(d.getClass())) {
        return (T)d;
    } else {
        return null;
    }
}

如果地图中的值不是正确的类T或其子类,则此代码将返回null。