Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't cast to to unspecific nested type with generics

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;
    }
}
like image 392
stacker Avatar asked Aug 26 '10 13:08

stacker


People also ask

Can you cast generic type Java?

The Java compiler won't let you cast a generic type across its type parameters because the target type, in general, is neither a subtype nor a supertype.

What is not allowed for generics Java?

To use Java generics effectively, you must consider the following restrictions: Cannot Instantiate Generic Types with Primitive Types. Cannot Create Instances of Type Parameters. Cannot Declare Static Fields Whose Types are Type Parameters.

What are the restrictions on generics?

One restriction of generics in Java is that the type parameter cannot be a primitive type. To understand why primitive data types don't work, let's remember that generics are a compile-time feature, meaning the type parameter is erased and all generic types are implemented as type Object.

Can I use polymorphism in generics?

The polymorphism applies only to the 'base' type (type of the collection class) and NOT to the generics type.


2 Answers

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).


A more generic 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:

  • Java generics is type invariant
  • There's a conversion from Integer to Number, but a List<Integer> is not a List<Number>
    • Similarly, a List<Integer> can be capture-converted by a List<?>, but a List<List<Integer>> is not a List<List<?>>
  • Using bounded wildcard, a List<? extends Number> can capture-convert a List<Integer>
    • Similarly, a 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!

Related questions

  • Multiple wildcards on a generic methods makes Java compiler (and me!) very confused
    • Very long and detailed exploration into this problem
  • Java Generic List<List<? extends Number>>
  • Any simple way to explain why I cannot do List<Animal> animals = new ArrayList<Dog>()?
  • What is the difference between <E extends Number> and <Number>?

See also

  • Java Generics Tutorial
    • Generics and Subtyping | Wildcards | More Fun with Wildcards
  • Angelika Langer's Java Generics FAQ
    • What is a bounded wildcard?
    • Which super-subtype relationships exist among instantiations of generic types?
like image 124
polygenelubricants Avatar answered Sep 30 '22 06:09

polygenelubricants


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).

like image 24
Ricky Clarkson Avatar answered Sep 30 '22 04:09

Ricky Clarkson