如何解决在Java中,强制转换由泛型实例类型的getClass返回的类始终安全吗?
我不确定如何以简洁的方式用措词表达这个问题的标题。我发现了一些相关的问题,例如this one,但似乎都没有一个人明确回答我的问题。
但实际上我要问的是:
考虑以下代码
static <A,B> Class<? extends A> getLeftClass(Pair<A,B> tuple) {
A left = tuple.getLeft();
return left.getClass();
}
按原样,此代码无法编译。编译失败并显示错误
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> tuple) {
A left = tuple.getLeft();
return (Class<? extends A>) left.getClass();
}
编译。但是,由于未选中强制转换,因此会有警告。
我的问题是,警告是否合理?有正当的理由不这样做吗?还是仅在这种情况下,编译器无法验证它是否正确,但是只要tuple.getLeft()
确实是A
的实例,它就始终可以工作?
顺便说一句,Pair
类是this one,来自Apache commons库
解决方法
警告是合理的,因为它又允许进行其他不会引起警告的不安全操作。 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");
这种情况称为堆污染,并且Java的泛型系统保证了这种情况不会出现带有免费警告的源代码。您会得到警告并有风险。
同样,我们可以做到:
List<String> stringList = getLeftClass(p)
.getConstructor(Collection.class).newInstance(listOfI);
assert stringList.get(0) instanceof String;// will fail
也有类似的第三方库,例如用于XML或JSON的反序列化器,在将Class
对象作为参数来描述假定的返回类型(或结果的组成部分)时,对类型安全性也有类似的假设。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。