声明在java中双重使用通配符

时间:2013-02-28 22:48:04

标签: java generics nested-generics

我无法为方法的输出声明一个完全通用的类型。 情况如下:

class A<S,T>{
public Callback<B<S,T>,C<S,T>> method();
}

在我的代码中我有其中一个;

A<String, ?> instance;

然而,当我打电话

result = instance.method()

使编译器满意的唯一方法是声明

Callback<?, ?> result = instance.method()

但我真的希望对我的仿制药更具体,并宣布

Callback<B<String, ?>,C<String, ?>> result = instance.method()

但是,由于每个通配符都是独立的,编译器会抱怨这是不正确的,声明它无法从

转换
Callback<B<String,capture#3-of ?>,C<String,capture#3-of ?>>

有没有办法正确宣布这种情况?

仅供参考,A,B和C类来自外部库。 我试图将我的实例声明为

A<String, Object>

但它也是我无法控制的第四类方法的结果:

class D<T>{
public A<T, ?> getObject();
}

D<String> start = new D<String>();
A<String, ?> = start.getObject();
...

2 个答案:

答案 0 :(得分:1)

你可以

Callback<? extends B<String, ?>, ? extends C<String, ?>> result
    = instance.method();

答案 1 :(得分:1)

这确实是一个尴尬的情况,是由于通配符捕获的限制以及来自D.getObject的不太理想的返回类型的结果。

有一些解决方法,但没有一个是漂亮的。首先是简单地做一个未经检查的演员:

@SuppressWarnings("unchecked") //it's okay for the two captures not to match
Callback<B<String, ?>, C<String, ?>> result =
        (Callback<B<String, ?>, C<String, ?>>)instance.method();

编辑:有些编译器会(更正确地)通过Callback<?, ?>进行双重投射:

@SuppressWarnings("unchecked") //it's okay for the two captures not to match
Callback<B<String, ?>, C<String, ?>> result =
        (Callback<B<String, ?>, C<String, ?>>)(Callback<?, ?>)instance.method();

您还可以使用辅助方法 - 这是通配符捕获问题的常见解决方案:

static <T> void helper(A<String, T> a) {

    Callback<B<String, T>, C<String, T>> result = a.method();

    //logic
}

...

helper(instance);

<强>更新

事实上,你可以将这两种方法结合起来,至少将丑陋地分离成一个辅助方法:

static <S, T> Callback<B<S, ?>, C<S, ?>> disentangleCallback(
        Callback<B<S, T>, C<S, T>> callback
) {
    @SuppressWarnings("unchecked") //it's okay for the two captures not to match
    final Callback<B<S, ?>, C<S, ?>> withWidenedTypes =
            (Callback<B<S, ?>, C<S, ?>>)(Callback<?, ?>)callback;
    return withWidenedTypes;
}

然后像这样使用它:

Callback<B<String, ?>, C<String, ?>> result =
        disentangleCallback(instance.method());

或者是一种类似的方法,它只需要A<S, T>并通过调用Callback<B<S, ?>, C<S, ?>>本身返回method,然后进行投射。


另一个想法:如果A的第二个类型参数总是是未知的,那么删除它并扩大method的返回类型可能更容易:< / p>

class A<S> {
    public Callback<B<S, ?>, C<S, ?>> method() { ... }
}

我意识到这将是一个不幸的让步,但如果T从未真正有用,那就有意义了。