带有无界通配符的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类型系统的特殊情况。 您将有一个问题,即说服编译器xx.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); } 

我认为它会起作用。