Common wildcards in Java generics
Suppose I have an interface
interface Foo<T> { void foo(T x); T bar() }
And this type of object with unknown parameters: foo Buzz Then I can call Baz foo(baz.bar()).
But now I need to add the value Baz Bar () is placed in a collection, and Baz. Above it is called later foo(). It's like
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));
This does not work:
List<Object> list; list.add(baz.bar()); ... baz.foo((???) list.get(1)); // I can't write down the type I need to cast to
Is there any way to do this?
Editor: the above is an oversimplification from my actual situation Say we have
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)); } }
Solution
This is an awkward question
The solution is to find a scope that contains the use of wildcards, place a type variable on it, replace the wildcard with a reference to the type variable, and then bind the type variable
In your case, it sounds like this class is a necessary scope So:
public class Whatever<T> { private List<T> list; private Foo<T> baz; public void bazToList() { list.add(baz.bar()); } public void listToBaz() { baz.foo(list.get(1)); } }
The problem is that you have added a type variable to the class Now, wherever this class is used, any type that mentions it needs a type binding (so whatever < string > or whatever ) It can be incredible if the code using this class doesn't really care about the type of things it keeps in the list
To solve this problem, you can create a generic holder class It's like:
public class Whatever { private WhateverHolder<?> holder; public void bazToList() { holder.bazToList(); } public void listToBaz() { holder.listToBaz(); } private static class WhateverHolder<T> { private List<T> list; private Foo<T> baz; public void bazToList() { list.add(baz.bar()); } public void listToBaz() { baz.foo(list.get(1)); } } }
But it's ugly You are introducing a new class and the runtime overhead of a new object just to solve some annoying generics