Jur*_*uru 8 java generics type-erasure
考虑这样的通用方法定义:
public static <T> T getParameter(final Context context, final ContextParameter contextParameter, final Class<T> clazz) {
return (T) context.get(contextParameter.name());
}
Run Code Online (Sandbox Code Playgroud)
在尝试像List <String>这样的通用对象之前,可以完美地获取任何类型的对象.我能使它工作的唯一方法是这样的:
final List<String> fileNames =
(List<String>) ContextUtils.getParameter(context,
ContextParameter.EOF_FILE_NAMES_TO_ZIP, List.class);
Run Code Online (Sandbox Code Playgroud)
但这需要额外的演员阵容,从而消除了使用该方法的目的.有没有办法提供List<String>.class或类似的方法?(我知道类型擦除可以防止List<String>存在,但也许有办法做到这一点).
注意:使其工作我的意思是没有类型安全警告.我知道代码可以正常工作,但它不是类型安全的.
如果不修改下游代码(context.get()),则无法以类型安全的方式执行此操作,因为泛型类型在运行时被擦除.实际上,目前该clazz参数根本没有被使用:你可以简单地删除该参数,并且该方法将执行相同(T)的操作,因为由于擦除,强制转换为当前的无操作.即使对于非genric类,您当前的代码也不是类型安全的.
因此,如果您不关心安全性,并且只是想避免在客户端代码中进行强制转换,则可以删除最后一个参数,并在方法上禁止一次警告.
如果你想要类型安全,你可以使用超类型令牌来保存泛型类型信息:Guava的TypeToken工作并且很容易获得(IMO每个Java项目都应该使用Guava).
但是,它需要对代码进行下游更改,因为您需要在添加对象时捕获类型信息,并在它们出现时进行检查.你没有为你的Context班级分享代码,所以很难说这是否可能,但无论如何你想要这样的东西:
static class TypedParam {
final TypeToken<?> type;
final Object object;
private TypedParam(TypeToken<?> type, Object object) {
this.type = type;
this.object = object;
}
}
public static class Context {
Map<String, TypedParam> params = new HashMap<>();
TypedParam get(String name) {
return params.get(name);
}
}
public static <T> T getParameter(final Context context, final String name, final TypeToken<T> type) {
TypedParam param = context.get(name);
if (type.isAssignableFrom(param.type)) {
@SuppressWarnings("unchecked")
T ret = (T)param.object;
return ret;
} else {
throw new ClassCastException(param.type + " cannot be assigned to " + type);
}
}
Run Code Online (Sandbox Code Playgroud)
基本上,您知道参数映射中所有对象的泛型类型,并在运行时使用"通用感知强制转换"进行检查.我没有在Context.put()上面添加,但您需要在添加参数时捕获类型信息.
你仍然有一个@SuppressWarnings("unchecked"),但在这里它可证明是类型安全的,因为你正在维护类型信息(在许多通用类的内容中你会发现可证明安全的类型,所以即使在正确的代码中也不能总是避免它们).