我有一个名为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
参数而没有泛型警告?
答案 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。