multiple nested wildcard - arguments not applicabl

2020-02-06 06:54发布

问题:

I've heavily simplified my problem. Here's how it reads.

I'm trying to figure out why the following code does not compile:

 List<AnonType<AnonType<?>>> l = new ArrayList<AnonType<AnonType<?>>>();
 l.add( new AnonType<AnonType<String>>() );

where

public class AnonType<T> {
  T a;

  List<T> b;
}

The compiler error is saying that add is not applicable for the argument given. OTOH, the following code with only 1-level nested wildcard compiles perfectly:

List<AnonType<?>> l = new ArrayList<AnonType<?>>();
l.add( new AnonType<String>() );

回答1:

The following compiles as expected:

    List<Set<? extends Set<?>>> list = new ArrayList<Set<? extends Set<?>>>();
    list.add(new HashSet<Set<String>>());
    list.add(new HashSet<Set<Integer>>());

The problem is that generics is type invariant.

Consider the simpler example:

  • Given that there is a casting conversion from Animal to Dog (e.g. Dog extends Animal)...
    • A List<Animal> IS NOT a List<Dog>
  • There is a capture conversion from List<? extends Animal> to a List<Dog>

Now here's what happens in this scenario:

  • Given that there is a capture conversion from Set<?> to Set<String>...
    • A Set<Set<?>> IS NOT a Set<Set<String>>
  • There is a capture conversion from Set<? extends Set<?>> to Set<Set<String>>

So if you want a List<T> where you can add a Set<Set<String>>, Set<Set<Integer>>, etc, then T is NOT Set<Set<?>>, but rather Set<? extends Set<?>>.

Related questions

  • Can't cast to to unspecific nested type with generics
  • Multiple wildcards on a generic methods makes Java compiler (and me!) very confused
  • 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?


回答2:

It doesn't compile because the type of the second argument in the Pair<,> of the statement is String and that type might not be the "unknown" type that was used in the declaration. I think it will compile if you replace the ? with Object. Of course, you will then lose compile-time type-checking.