[英]Generics method call with wildcard
I have a method submit
: 我有一个方法
submit
:
<T> Future<Optional<T>> submit(Value<T> value) {
//...
}
and a call of this method. 并呼吁这种方法。
Value<?> value = null;
Future<Optional<?>> future = submit(value);
But it does not compile unless I change the signature to Future<? extends Optional<?>> future
但它不会编译,除非我将签名更改为
Future<? extends Optional<?>> future
Future<? extends Optional<?>> future
because submit
returns Future<Optional<caputure of ?>>
which is not Future<Optional<?>>
since generics are invariant. Future<? extends Optional<?>> future
因为submit
返回Future<Optional<caputure of ?>>
,它不是Future<Optional<?>>
因为泛型是不变的。 Is there any way to give a hint to a compiler and call the method submit
so it returns Future<Optional<?>>
? 有没有办法给编译器一个提示并调用方法
submit
这样它返回Future<Optional<?>>
?
This snippet 这个片段
<T, E extends Future<Optional<T>>> E submit(Value<T> value) {
// ...
}
Value<?> value = null;
Future<Optional<?>> future = submit(value);
compiles as well but then I need to do unsafe cast to E before returning the value. 编译也是如此但我需要在返回值之前对E进行不安全的转换。
Here is an answer explaining the generics invariance but it still does not answer how to work with captured types. 这是一个解释泛型不变性的答案,但它仍然没有回答如何使用捕获的类型。
Multiple wildcards on a generic methods makes Java compiler (and me!) very confused 泛型方法上的多个通配符使Java编译器(和我!)非常混淆
Although I'm not sure why using it as Future<? extends Optional<?>>
虽然我不确定为什么将它用作
Future<? extends Optional<?>>
Future<? extends Optional<?>>
should be a problem, there may be a solution, depending on how many contortions and "tricks" you are willing to accept. Future<? extends Optional<?>>
应该是一个问题,可能有一个解决方案,取决于你愿意接受多少扭曲和“技巧”。
It is not possible to compile it in the desired form, even when using the additonal type parameter E
, simply because it is not type safe. 即使使用additonal类型参数
E
,也不可能以所需的形式编译它,因为它不是类型安全的。 At least, it is not possible (for the compiler) to make sure that it is type safe. 至少,(编译器)不可能确保它是类型安全的。 The reason why it could not be type safe can be summarized as follows: Someone receiving the
Future<Optional<?>>
could modify the Future
, and assign it any Optional
- even one that has a different type than the one that it was originally created with. 它可能不是类型安全的原因可归纳如下:接收
Future<Optional<?>>
可以修改Future
,并为其分配任何Optional
- 即使是与原来的类型不同的类型用。创建。 At a different location, someone could know the Future
with its original type, and receive a ClassCastException
when trying to use it. 在不同的位置,有人可以使用其原始类型了解
Future
,并在尝试使用它时收到ClassCastException
。 (I explained this with a simpler example in https://stackoverflow.com/a/22193221/3182664 ) (我在https://stackoverflow.com/a/22193221/3182664中用一个更简单的例子解释了这一点)
... all this is not relevant here. ......这一切都与此无关。 The
Future
interface does not allow to "set" any new value. Future
接口不允许“设置”任何新值。 Thus, it is perfectly feasible to convert it into a Future
with a supertype of its original type. 因此,将其转换为具有其原始类型的超类型的
Future
是完全可行的。
Note: This is similar to the fact that you can write 注意:这类似于您可以编写的事实
List<Integer> integers = new ArrayList<Integer>();
List<Number> numbers = Collections.unmodifiableList(integers);
This is valid (meaning "type safe") because you can not pollute the Integer
-list with invalid Number
instances (like Double
s), because it's not possible to modify the list anyhow! 这是有效的(意思是“类型安全”),因为你不能用无效的
Number
实例(比如Double
s)污染Integer
-list,因为无论如何都无法修改列表!
So one type-safe, warning-free and valid solution could be to introduce a method that "wraps" a Future<? extends T>
因此,一种类型安全,无警告且有效的解决方案可能是引入一种“包裹”
Future<? extends T>
Future<? extends T>
and returns it as a Future<T>
. Future<? extends T>
并将其作为Future<T>
返回。 Again: This is not really pretty, and may not be worth the effort, but at least one option: 再说一遍:这不是很漂亮,可能不值得努力,但至少有一个选择:
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class GenericOptionalFutureMethod
{
void call()
{
Value<?> value = null;
Future<Optional<?>> future =
FutureWrapper.<Optional<?>>wrap(submit(value));
}
<T> Future<Optional<T>> submit(Value<T> value) {
return null;
}
}
class FutureWrapper
{
static <T> Future<T> wrap(final Future<? extends T> future)
{
return new Future<T>()
{
@Override
public boolean cancel(boolean mayInterruptIfRunning)
{
return future.cancel(mayInterruptIfRunning);
}
@Override
public boolean isCancelled()
{
return future.isCancelled();
}
@Override
public boolean isDone()
{
return future.isDone();
}
@Override
public T get() throws InterruptedException, ExecutionException
{
return future.get();
}
@Override
public T get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException,
TimeoutException
{
return future.get();
}
};
}
}
As far as I know there is no way of telling the compiler that your code is actually correct. 据我所知,没有办法告诉编译器你的代码实际上是正确的。 You can try replacing the
?
你可以尝试更换
?
with Object
: 与
Object
:
Value<Object> value = null;
Future<Optional<Object>> future = submit(value);
I don't see where the problem is really. 我不知道问题出在哪里。
Future<? extends Optional<?>> future = submit(value);
Optional<?> f = future.get();
Compiles and runs correctly. 编译并正确运行。
The answer you linked to explains it quite clearly: 您链接的答案非常清楚地解释了:
Foo<Bar>
is a Foo<?>
Foo<Bar>
是一个Foo<?>
But 但
Foo<Bar<X>>
isn't a Foo<Bar<?>>
, it's a Foo<? extends Bar<?>>
Foo<Bar<X>>
不是Foo<Bar<?>>
,它是Foo<? extends Bar<?>>
Foo<? extends Bar<?>>
You can change your method to use a wildcard operator as a parameter, since you are not specifying any type on T
. 您可以更改方法以使用通配符运算符作为参数,因为您没有在
T
上指定任何类型。 Seems to me, that it wouldn't change much. 在我看来,它不会有太大变化。
Future<Optional<?>> submit(Value<?> value) {
//...
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.