在Java泛型中共享通配符

Ale*_*nov 3 java generics bounded-wildcard

假设我有一个界面

interface Foo<T> { 
    void foo(T x); 
    T bar() 
}
Run Code Online (Sandbox Code Playgroud)

以及具有未知参数的此类对象:Foo<?> baz.然后我可以打电话baz.foo(baz.bar()).

但是,现在我需要将值baz.bar()放入集合中,baz.foo()稍后再调用它.就像是

List<???> list; // can I tell the compiler this is the same type as baz's wildcard?
list.add(baz.bar());
...
baz.foo(list.get(1));
Run Code Online (Sandbox Code Playgroud)

这也不起作用:

List<Object> list;
list.add(baz.bar());
...
baz.foo((???) list.get(1)); // I can't write down the type I need to cast to
Run Code Online (Sandbox Code Playgroud)

有没有办法做到这一点?

编辑:以上是从我的实际情况过分简化.说我们有

class Bar {
    private final Foo<?> foo;
    private List<???> list; // the type argument can be selected freely

    Bar(Baz baz) {
        foo = baz.getFoo(); // returns Foo<?>, can't be changed 
    }

    void putBar() {
        list.add(foo.bar());
    }

    void callFoo() {
        foo.foo(list.get(0));
    }
}
Run Code Online (Sandbox Code Playgroud)

Luk*_*der 7

您可以将逻辑包装在这样的泛型方法中:

public <T> void myMethod(Foo<T> baz) {
  List<T> list; // initialise it...
  list.add(baz.bar());
  // ...
  baz.foo(list.get(1));
}
Run Code Online (Sandbox Code Playgroud)

这是我所知道的唯一方式,实现你想要的,而不需要不安全的铸造.

OP编辑后:

正如其他人所提到的,外部类Bar需要知道常见的泛型类型T.此外,随着您不能够改变的签名的约束Baz.getFoo(),我想你必须投不安全Foo<?>Foo<T>在构造函数Bar<T>:

class Bar<T> {

    private final Foo<T> foo;
    private List<T> list;

    Bar(Baz baz) {
        // Since baz cannot be changed, you will have to
        // unsafe cast Foo<?> to Foo<T> here.
        foo = (Foo<T>) baz.getFoo();
    }

    void putBar() {
        list.add(foo.bar());
    }

    void callFoo() {
        foo.foo(list.get(0));
    }
}
Run Code Online (Sandbox Code Playgroud)

或者(因为Foo,Bar,Baz不是理解你的真实用例的好方法),你仍然可以避免这样的泛化Bar:

class Bar {

    private final Foo<Object> foo;
    private List<Object> list;

    Bar(Baz baz) {
        // Since baz cannot be changed, you will have to
        // unsafe cast Foo<?> to Foo<Object> here.
        foo = (Foo<Object>) baz.getFoo();
    }

    void putBar() {
        list.add(foo.bar());
    }

    void callFoo() {
        foo.foo(list.get(0));
    }
}
Run Code Online (Sandbox Code Playgroud)