Reputation: 68942
I have two classes with nested generics. Is there a way to get rid of the
Type mismatch: cannot convert from Msg<Value<String>>
to Msg<Value<?>>
error ?
In the last assignment
public class Value<V> {
V val;
public Value(V val) {
this.val = val;
}
@Override
public String toString() {
return "" + val;
}
}
public class Msg<T> {
T holder;
public Msg( T holder) {
this.holder = holder ;
}
public String toString() {
return "" + holder;
}
public static void main(String[] args) {
Msg<Value<String>>strMsg = new Msg(new Value<String>("abc"));
// This is OK
Msg<?>objMsg = strMsg;
// Type mismatch: cannot convert from Msg<Value<String>> to Msg<Value<?>>
Msg<Value<?>>objMsg = strMsg;
}
}
Upvotes: 13
Views: 5995
Reputation: 383726
Use the following:
Msg<? extends Value<?>> someMsg = strMsg;
The problem is that the ?
in Msg<Value<?>> objMsg
is NOT capable of capture conversion. It's not "a Msg
of Value
of some type. It's "a Msg
of Value
of ANY type".
This also explains why along with the declaration change, I've also renamed the variable to someMsg
. The Value
can't just be any Object
. It must belong to some type (String
in this example).
Let's consider a more generic example of a List<List<?>>
. Analogously to the original scenario, a List<List<?>>
can NOT capture-convert a List<List<Integer>>
.
List<List<Integer>> lolInt = null;
List<List<?>> lolAnything = lolInt; // DOES NOT COMPILE!!!
// a list of "lists of anything"
List<? extends List<?>> lolSomething = lolInt; // compiles fine!
// a list of "lists of something"
Here's another way to look at it:
Integer
to Number
, but a List<
Integer
>
is not a List<
Number
>
List<Integer>
can be capture-converted by a List<?>
, but a List<
List<Integer>
>
is not a List<
List<?>
>
List<? extends
Number
>
can capture-convert a List<
Integer
>
List<? extends
List<?>
>
can capture-convert a List<
List<Integer>
>
The fact that some ?
can capture and others can't also explains the following snippet:
List<List<?>> lolAnything = new ArrayList<List<?>>(); // compiles fine!
List<?> listSomething = new ArrayList<?>(); // DOES NOT COMPILE!!!
// cannot instantiate wildcard type with new!
List<List<? extends Number>>
List<Animal> animals = new ArrayList<Dog>()
?<E extends Number>
and <Number>
?Upvotes: 24
Reputation: 2939
My answer is similar to another, but hopefully is more clear.
List<List<?>> is a list of (lists of anything).
List<List<String>> is a list of (lists of strings).
The latter cannot be converted to the former because doing so would allow you to add a List<Number> to your List<List<String>>, which would clearly be broken.
Note that the rules for this don't change if you replace List with some type that doesn't have .add. Java would need declaration-site covariance and/or contravariance for that (like C#'s IEnumerable<out T> or Scala's List[+A]). Java only has use-site covariance and contravariance (? extends X, ? super X).
Upvotes: 4
Reputation: 18333
ILMTitan has a good solution, and if you don't want to make the class specific to Value you may as well use the base type instead of generics at this point because you'll be turning off a safety feature, but there is a way. You might even be able to pass a parameter to make this method more generic, but the key is "@SuppressWarnings".
@SuppressWarnings("unchecked")
Msg<Value<?>> convert()
{
return (Msg<Value<?>>) this;
}
Upvotes: 0
Reputation: 11017
Although your generic type parameter contains a wildcard, it is not itself a wildcard. When assigning to a variable (Msg<T>
) with a non-wildcard generic type T
, the object being assigned must have exactly T
as its generic type (including all generic type parameters of T
, wildcard and non-wildcard). In your case T
is Value<String>
, which is not the same type as Value<?>
.
What you can do, because Value<String>
is assignable to Value<?>
, is use the wildcard type:
Msg<? extends Value<?>> a = new Msg<Value<String>>();
Upvotes: 3
Reputation: 19050
Not a direct answer but i strongly recommend the reading of: http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf to better understand generics.
Upvotes: 1