带有无界通配符的Javagenerics?
我有一个将对象转换为字符串的接口:
public interface Converter { String asString(T object); }
以及存储所有可用转换器的地图:
Map<Class, Converter> converterMap;
现在我有一个要转换的异构数据列表,如下所示:
List data = fetchData(); List stringData = new ArrayList(data.size()); for (Object datum : data) { stringData.add(convertrMap.get(datum.getClass()).asString(datum)); }
但是这段代码没有编译:
error: method asString in interface Converter 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 void helper(List data) { Map, Converter > converterMap = null; List stringData = null; for (T datum : data) { stringData.add(converterMap.get(datum.getClass()).asString(datum)); } }
调用此帮助方法如下
List> data = fetchData(); helper(data);
首先,您应该将地图封装在这样的辅助类中,其操作保留不变量( Class
映射到Converter
):
public class ConverterMap { Map, Converter>> converterMap = new HashMap, Converter>>(); public void addConverter(Class clazz, Converter converter) { converterMap.put(clazz, converter); } @SuppressWarnings("unchecked") public Converter getConverter(Class clazz) { return (Converter )converterMap.get(clazz); } }
现在,为了分解任务,让我们采取小步骤编写一个函数,该函数接受任何对象并根据转换器映射转换它(假设对象的类在转换器映射中):
ConverterMap cm = new ConverterMap; private static String convert(Object x);
这看起来很简单,但比它看起来更难,因为你将在类型.getClass()
类型中.getClass()
Java类型系统的特殊情况。 您将有一个问题,即说服编译器x
是x.getClass()
参数的一个实例。 解决这个问题的最佳方法是:
@SuppressWarnings("unchecked") private static String convert2(Class 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); }
我认为它会起作用。