具有无界通配符的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));
}