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
