我有一个HTTP执行器类:
Future<? extends Response> future = service.apply(request).toJavaFuture();
现在,我想删除其中的? extends部分,因为我不想使它对调用者如此通用。基本上,我想返回Future<Response>。
在我看来:
x extends y
这意味着x是y,y不是x。
这意味着x可以被抛给y。
在我看来,这是安全的,因为x总是扩展y。
为什么以下是不安全的?
Future<? extends Response> future = service.apply(request).toJavaFuture();
Future<Response> futureResponse = (Future<Response>) future;发布于 2019-05-14 12:44:20
可以为Future<? extends Response>变量分配Future<Response>、Future<ResponseSubClass1>或Future<ResponseSubClass2>。
Future<ResponseSubClass1>实例不能安全地分配给Future<Response>变量,因为这将允许将ResponseSubClass2分配给Future<ResponseSubClass1>。
因此,您的尝试转换是不安全的。
发布于 2019-05-14 13:38:31
我想说,这是编译器对泛型类型参数的限制。编译器知道您正在参数化这个类,但是它没有任何上下文来说明如何使用它。
您的Future是一个数据持有者。你不能在里面放任何东西,你只能得到它的请求。在这种情况下,您期望Future<? extends Response>和Future<Response>的行为方式是相同的,因此可以安全地进行转换,这是完全合理的。这两件事都是请求的提供者。确切的实例可能是子类,但是无论我们从Future中得到什么,都肯定会实现Request的方法,因此这种转换看起来应该是安全的。
当您的类不是纯供应商,而是它们正在使用数据时,问题就出现了。假设我们向Future添加了一个方法来设置值:
interface Future<T>
{
void setValue(T value);
//...
}我们有一个Future<? extends Response>,它是作为Future<ChildResponse>创建的。当我们将其转换为Future<Response>时,我们现在可以用Response调用setValue,而在转换之前我们需要一个ChildResponse。这就是为什么演员被认为不安全的原因。
实际上,编译器不够聪明,无法区分这两种情况,所以最好的决定就是始终将强制转换声明为不安全的。即使编译器能够区分这一点,接口也会改变--假设Future如前所述--使得以前安全的转换不再是安全的,这使得问题变得更加复杂。
在这种情况下,我个人认为压制警告会很好。强制转换就是向编译器断言您有它没有的信息,这就是您所处的情况。
https://stackoverflow.com/questions/56130764
复制相似问题