[英]Generic Type Argument checked by Class Parameter can be hacked, any better ways?
考虑一下类:
class OnlyIntegerTypeAllowed<T> {
OnlyIntegerTypeAllowed(Class<T> clazz) {
System.out.println(clazz);
if (clazz != Integer.class)
throw new RuntimeException();
}
}
它被设计为仅接受Integer
类型参数。 我们在其构造函数中添加了一个if-throw
检查。 这是检查类型参数的一种非常常用的方法。
但是,可以通过以下方式绕过(检查,欺骗)此检查:
OnlyIntegerTypeAllowed<Integer> normalWay =
new OnlyIntegerTypeAllowed<Integer>(Integer.class);
OnlyIntegerTypeAllowed<String> hacking =
new OnlyIntegerTypeAllowed<String>((Class<String>) Class.forName(Integer.class.getName()));
上述两种线都没有编译错误和没有抛出异常!
OMG-有什么更好的方法来执行类型参数?
欢迎进行擦除 。 在运行时, Class<T>
已被擦除为Class
-JVM,源代码中的Class<Integer>
, Class<String>
等都看起来相同。 这就是未经检查的强制转换的意思-开发人员要自己承担风险,因为如果错误的话,它不会因ClassCastException
而快速失败。 取而代之的是,稍后的ClassCastException
可能会在类型擦除过程中由编译器插入的强制转换中发生。 通用类型的引用指向不应该允许的对象的状态称为堆污染 。
OMG-有什么更好的方法来执行类型参数?
不,就泛型类型安全而言,这是Java所能提供的最好的-实际上它是可选的。 懒惰或滥用代码可以随意执行未经检查的强制转换或使用原始类型 (将隐式未经检查的强制转换引入其所触摸的任何内容),尽管许多IDE都提供使这些编译器错误而不是发出警告的功能。
附带说明一下,未经检查的强制转换有时是有效的,例如,在实现Joshua Bloch的有效Java项目27“偏爱的通用方法”时:
private static final Comparator<Object> HASH_CODE_COMPARATOR =
new Comparator<Object>() {
@Override
public int compare(final Object o1, final Object o2) {
return Integer.compare(o1.hashCode(), o2.hashCode());
}
};
public static <T> Comparator<T> hashCodeComparator() {
@SuppressWarnings("unchecked") // this is safe for any T
final Comparator<T> withNarrowedType =
(Comparator<T>)(Comparator<?>)HASH_CODE_COMPARATOR;
return withNarrowedType;
}
在这里,选中转换是安全的,因为HASH_CODE_COMPARATOR
行为contravariantly 。 它是无状态的,并且适用于任何Object
,因此我们可以让调用者确定其通用类型:
Comparator<String> c = hashCodeComparator();
在这种情况下,我们可以使用@SuppressWarnings("unchecked")
删除未经检查的警告,从本质上告诉编译器信任我们。 添加解释性注释也是一个好主意。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.