繁体   English   中英

Java泛型与无界通配符?

[英]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()特殊情况。 您将不得不说服编译器说xx.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM