[英]Java generics with unbounded wildcard?
我有一个接口将对象转换为字符串:
public interface Converter<T> {
String asString(T object);
}
并存储所有可用转换器的地图:
Map<Class<?>, Converter<?>> converterMap;
现在,我有了要转换的异构数据列表,如下所示:
List<?> data = fetchData();
List<String> stringData = new ArrayList<>(data.size());
for (Object datum : data) {
stringData.add(convertrMap.get(datum.getClass()).asString(datum));
}
但是此代码无法编译:
error: method asString in interface Converter<T> cannot be applied to given types;
stringData.add(converterMap.get(datum.getClass()).asString(datum));
required: CAP#1
found: Object
reason: actual argument Object cannot be converted to CAP#1 by method invocation conversion
where T is a type-variable:
T extends Object declared in interface Converter
where CAP#1 is a fresh type-variable:
CAP#1 extends Object from capture of ?
我应该如何更改代码?
您面临的问题称为通配符捕获 。 Java无法识别将从List<?>
数据接收的类型。 尝试以两种方式中的任何一种重构代码
方法1:如下更改您的界面
interface Converter {
String asString(Object object);
}
方法2: Helper方法通过类型推断来捕获通配符
创建如下的帮助方法,
// Helper method created so that the wildcard can be captured
// through type inference.
private <T> void helper(List<T> data) {
Map<Class<?>, Converter<T>> converterMap = null;
List<String> stringData = null;
for (T datum : data) {
stringData.add(converterMap.get(datum.getClass()).asString(datum));
}
}
如下调用此辅助方法
List<?> data = fetchData();
helper(data);
首先,您应该将地图封装在这样的帮助器类中,该类的操作保留不变性( Class<T>
映射到Converter<T>
):
public class ConverterMap {
Map<Class<?>, Converter<?>> converterMap = new HashMap<Class<?>, Converter<?>>();
public <T> void addConverter(Class<T> clazz, Converter<T> converter) {
converterMap.put(clazz, converter);
}
@SuppressWarnings("unchecked")
public <T> Converter<T> getConverter(Class<T> clazz) {
return (Converter<T>)converterMap.get(clazz);
}
}
现在,要分解任务,让我们花一点时间编写一个函数,该函数接受任何对象并根据转换器映射对它进行转换(假定对象的类在转换器映射中):
ConverterMap cm = new ConverterMap;
private static String convert(Object x);
这看起来很简单,但是却很难,因为您会在Java类型系统的.getClass()
类型方面.getClass()
特殊情况。 您将不得不说服编译器说x
是x.getClass()
参数实例的问题。 解决此问题的最佳方法是:
@SuppressWarnings("unchecked")
private static <T> String convert2(Class<T> clazz, Object x) {
return cm.getConverter(clazz).asString((T)x);
// you can alternately do clazz.cast(x) instead of the unchecked cast (T)x
}
private static String convert(Object x) {
return convert2(x.getClass(), x);
}
然后您可以解决其余问题:
for (Object datum : data) {
stringData.add(convert(datum));
}
您应该像这样更改代码:
public interface Converter {
String asString(Object object);
}
我认为它将起作用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.