Wil*_*ver 6 java generics casting type-erasure
我不知道如何用简洁的方式来表达这个问题的标题。我发现了一些相关的问题,例如这个,但似乎没有一个能明确回答我提出的问题。
但基本上我要问的是:
考虑以下代码
static <A, B> Class<? extends A> getLeftClass(Pair<A, B> tuple) {
A left = tuple.getLeft();
return left.getClass();
}
Run Code Online (Sandbox Code Playgroud)
按原样,此代码无法编译。编译失败并出现错误
Type mismatch: cannot convert from Class<capture#20-of ? extends Object> to Class<? extends A>
我认为这本质上是因为getClass返回一个类型,Class<? extends Object>但编译器期望Class<? extends A>.
一种解决方案是将类转换如下:
static <A, B> Class<? extends A> getLeftClass(Pair<A, B> tuple) {
A left = tuple.getLeft();
return (Class<? extends A>) left.getClass();
}
Run Code Online (Sandbox Code Playgroud)
这编译。但是,由于未经检查的强制转换,会出现警告。
我的问题是,警告是否合理?有正当理由不这样做吗?或者这只是编译器无法验证它是否正确的情况,但只要tuple.getLeft()它确实是 的实例,它就会始终工作A?
顺便说一下,这个Pair类是这个,来自 Apache 公共库
该警告是合理的,因为它反过来允许其他不会引起警告的不安全操作。的类型参数Class允许您执行动态运行时转换和实例化,并且这些操作的类型安全性取决于类型参数的有效性。
换句话说,您的方法允许执行以下操作:
Pair<List<String>,?> p = Pair.of(new ArrayList<>(), null);
List<Integer> listOfI = new ArrayList<>(Arrays.asList(1, 2, 3));
List<String> listOfS = getLeftClass(p).cast(listOfI);
listOfS.set(1, "foo");
Run Code Online (Sandbox Code Playgroud)
这种情况称为堆污染,Java 的泛型类型系统保证在无警告的源代码中不会发生这种情况。您会收到警告并面临风险。
同样,我们可以这样做:
List<String> stringList = getLeftClass(p)
.getConstructor(Collection.class).newInstance(listOfI);
assert stringList.get(0) instanceof String;// will fail
Run Code Online (Sandbox Code Playgroud)
有类似的第 3 方库,例如 XML 或 JSON 的反序列化器,在提供对象Class作为参数来描述假定的返回类型(或结果的组件)时,对类型安全具有类似的假设。