Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/374.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
具有无界通配符的Java泛型?_Java_Generics_Map_Wildcard - Fatal编程技术网

具有无界通配符的Java泛型?

具有无界通配符的Java泛型?,java,generics,map,wildcard,Java,Generics,Map,Wildcard,我有一个将对象转换为字符串的接口: public interface Converter<T> { String asString(T object); } 公共接口转换器{ 字符串关联(T对象); } 以及存储所有可用转换器的地图: Map<Class<?>, Converter<?>> converterMap; Map>converterMap; 现在我有一个要转换的异构数据列表,如下所示: List<?> dat

我有一个将对象转换为字符串的接口:

public interface Converter<T> {
    String asString(T object);
}
公共接口转换器{
字符串关联(T对象);
}
以及存储所有可用转换器的地图:

Map<Class<?>, Converter<?>> converterMap;
Map>converterMap;
现在我有一个要转换的异构数据列表,如下所示:

List<?> data = fetchData();
List<String> stringData = new ArrayList<>(data.size());
for (Object datum : data) {
    stringData.add(convertrMap.get(datum.getClass()).asString(datum));
}
public interface Converter {
    String asString(Object object);
}
List data=fetchData();
List stringData=newarraylist(data.size());
用于(对象基准:数据){
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 ?
错误:接口转换器中的方法asString无法应用于给定类型;
add(converterMap.get(datum.getClass()).asString(datum));
必填项:第1章
发现:对象
原因:无法通过方法调用转换将实际参数对象转换为CAP#1
其中T是一个类型变量:
T扩展接口转换器中声明的对象
其中CAP#1是一个新类型变量:
CAP#1将对象从捕获扩展到?

我应该如何更改代码?

您面临的问题是。 Java无法识别将从
列表
数据接收的类型。 试着用这两种方法中的任何一种重构代码

方法1:如下更改界面

interface Converter {
    String asString(Object object);
}
方法2:通过类型推断捕获通配符的助手方法

创建一个助手方法,如下所示

// 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));
    }
}
//创建帮助器方法以便捕获通配符
//通过类型推断。
专用void帮助器(列表数据){
映射数据=fetchData();
助手(数据);

您应该这样更改代码:

List<?> data = fetchData();
List<String> stringData = new ArrayList<>(data.size());
for (Object datum : data) {
    stringData.add(convertrMap.get(datum.getClass()).asString(datum));
}
public interface Converter {
    String asString(Object object);
}

我认为它会起作用。

首先,您应该像这样将映射封装在一个helper类中,该类的操作保持不变(即
映射到
转换器
):

这看起来很简单,但比看起来更难,因为Java类型系统在如何键入
.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);
}

为什么不使用
asString(Object-Object)
而不是使用
Converter
,然后使用
Converter
它使泛型变得多余。这可以工作,但类型信息丢失,使得
asString
方法不安全,例如,我可以安全地使用
Converter-dateConverter=(Converter)converterMap.get(Date.class)
。我看不出它是如何使它不安全的。如果您错误地映射了转换器对象和类,即使您当前的设计也是不安全的。类似于
converter c=new converter;c.asString(“abc”)的语句;
是非法的,因为
在运行时是未知的,因此它只需要此未知类型的某些子类型。我认为将参数类型更改为
对象
是不安全的,例如,我可以调用
字符串(“”)
在整数转换器上。我还有一些其他代码需要此类型信息。如果您不使用
转换器中的
T
有什么意义?
@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));
}