简体   繁体   English

泛型方法调用通配符

[英]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中用一个更简单的例子解释了这一点)

But... 但...

... 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM