Java泛型-获取类的实例

Java泛型-获取类的实例,java,generics,Java,Generics,我有一个名为Data的抽象类,带有一个getInstance()方法,该方法应该返回数据的具体子类的实例 我想向getInstance方法传递一个字符串,该字符串将准确定义将返回的类 到目前为止,我已经: public abstract class Data { private Map<String, Data> instances; public <T extends Data> T getInstance(Class<T> type, Str

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

我想向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)); 
  }

}
公共抽象类数据{
私有地图实例;
public T getInstance(类类型,字符串数据名){
返回type.cast(instances.get(dataName));
}
}
其中getInstance()方法在
instances
映射中查找正确的实例。我认为,如果映射是由Spring填充的,那么这应该是可以的,但是调用者必须将
类类型
参数与
字符串dataName
参数相匹配


是否有任何方法可以删除
类类型
参数而不出现泛型警告?

您可以完全跳过类参数

public <T extends Data> T getInstance(String dataName) {
    return (T)instances.get(dataName);
}
public T getInstance(字符串数据名){
return(T)instances.get(dataName);
}
这仍将生成一个警告(您可以抑制该警告)。如果映射中的实际类与预期类型不同,则这两种方法都将引发运行时异常。在我的示例中,编译类型推断在某些情况下不起作用,在像这样调用时需要指定类型:
Data.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;
    }
}
public T getInstance(类clazz,字符串dataName){
数据d=instances.get(dataName);
如果(d!=null&&clazz.isAssignableFrom(d.getClass())){
返回(T)d;
}否则{
返回null;
}
}

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

否,如果您在不知道该类型的运行时类的情况下尝试强制转换为泛型类型,则始终会收到警告。不,如果不将泛型类作为参数提供,则无法获取泛型类的实例-泛型在运行时被擦除

在没有显式强制转换的情况下不获取警告的唯一方法是返回对象或数据(取决于地图),并要求用户进行强制转换:

public Data getInstance(String dataName) {
    return instances.get(dataName); 
}
// OR
public Object getInstance(String dataName) {
    return instances.get(dataName); 
}
在我看来,最好同时提供两种方法以方便使用:
datagetinstance(String)
tgetinstance(Class,String)
。这本质上也是OSGI在类中所做的,因此可以获取服务引用,但不同的是,不可能获取具有任意id的服务(id始终是类的名称):

servicerence BundleContext#getservicerence(java.lang.String clazz)
ServiceReference BundleContext#getServiceReference(java.lang.Class clazz)

这不符合我的要求。考虑另一个解决方案。我想,如果我能想出一个,你使用字符串来识别类型的理由是什么?如果你能避免,就这样做。通过依赖字符串(不能在编译时进行检查)来识别具体类型,您的系统在运行时会面临很大的风险。这种方法从根本上说是类型不安全的。调用代码可以任意选择返回类型。是的,但是带有
Class
参数的解决方案也是如此,因为您可以这样调用
DataSubclass1 s=Data.getInstance(DataSubclass1.Class,“keyForDataSubclass2Instance”)
,这将引发运行时异常。它将在我们显式进行运行时强制转换的位置引发预期的异常。它不会造成堆污染,也就是说,某一类型的表达式在运行时实际上会指向该类型,并在其他没有强制转换的地方导致异常。在这两种情况下,运行时强制转换都是在return语句中的
getInstance
方法中进行的,因此这将是这两种情况下异常的来源。不,在您的方法中,
getInstance
方法中没有运行时强制转换。
ServiceReference<?> BundleContext#getServiceReference(java.lang.String clazz) 
ServiceReference<S> BundleContext#getServiceReference(java.lang.Class<S> clazz)