2

I thought I understood this but obviously not...

I have a method signature like so:

void doSomething(List<TypeA> typeAs){...}

List<TypeA<TypeB>> getTypeBTypeAs(){...}

but if I try and call

doSomething(getTypeBTypeAs());

I get a compile error: "the method doSomething(List) in the type ... is not applicable for the arguments (List>)"

however if i change the sig of doSomething to

void doSomething(List<TypeA<?>> typeAs){...}

it still doesn't work, but

void doSomething(List typeAs){...}

obviously it works as i bypass generics.

which seems odd.

Can someone fill me in?

Also, in this case I'd like doSomething to work with any List containing TypeAs of any generic type; undefined, TypeB, TypeC etc.

thanks.

pstanton
  • 35,033
  • 24
  • 126
  • 168

2 Answers2

4

A generic class TypeA<TypeB> is a different type from TypeA. You can't pass in a parameter of type TypeA<TypeB> where the method expects a TypeA. Also TypeA<TypeB> is a different type from TypeA<TypeC>, so the same constraints apply.

The classic example (from Effective Java, 2nd Ed. AFAIR) is: we have containers for animals (Container<Animal>) and as subclasses of Animal we have Lion and Butterfly. Now, if you have a method

void func(Animal animal);

it will accept both lions and butterflies. However, this function

void func(Container<Animal> animalContainer);

will not accept a Container<Lion>, neither a Container<Butterfly>. Do realize that a strong cage useful for keeping lions safely would not stop butterflies from flying away, and vice versa a thick but light net to hold butterflies would not stand a chance against a lion.

If you really are sure that any kind of animal container suits you, declare your function like this:

void func(Container<? extends Animal> animalContainer);

Back to your case, I guess the only method to accept both List<TypeA> and List<TypeA<TypeB>> would be something like this:

void doSomething(List<?> list);
Péter Török
  • 114,404
  • 31
  • 268
  • 329
  • If Effective Java has a generics example, it must be in the second edition, because I have the first edition sitting on my desk, and it's several years older than Java 5. – Powerlord Feb 18 '10 at 21:42
  • yes, it's in the second edition. And it's available online, google it (Effective Java Generics) – Bozho Feb 18 '10 at 21:44
  • Also, if you did want the second func to accept a Container containing any animal, it would be `void func(Container extends Animal> animalContainer);` would it not? – Powerlord Feb 18 '10 at 21:44
  • 1
    then how do i set up a method ie `doSomething` to accept a list containing any incarnation of `List` ? – pstanton Feb 18 '10 at 21:46
  • Thanks guys for the comments, I added a link to the book. @R. Bemrose As chance would have it, I added the same solution at the same time :-) – Péter Török Feb 18 '10 at 21:53
  • @pstanton Could you specify more exactly what you mean by "any incarnation of `List`" ? – Péter Török Feb 18 '10 at 21:56
  • AHHHHHHHHHHHA! so `List>` will match `List extends TypeA>` .. that's what i didn't understand. I thought that was designed for where `class TypeB extends TypeA` you could assign a `List` to `List extends TypeA>`. that's a little misleading, but i guess it works!. thx. – pstanton Feb 18 '10 at 21:59
  • @pstanton I added an answer to your previous question. I am afraid that since `TypeA>` is not a `TypeA` (unless `TypeA` is a standard library container), this won't work. – Péter Török Feb 18 '10 at 22:05
  • no, that doesn't work, but you've already answered my question... `List extends TypeA>` does match `List` as well as `List>`, which is all i need. thx. – pstanton Feb 19 '10 at 06:15
0

Try this:

<T> void doSomething(List<TypeA<T>> typeAs) { ... }

Note the <T> at the beginning of the line. That way doSomething accepts every List containing any TypeAs.

stmax
  • 6,506
  • 4
  • 28
  • 45