Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Generics - Expected return type different than actual

Tags:

java

generics

Here is an example of some code I'm working on:

public interface FooMaker<T extends Enum<T> & FooType>
{
      public List<Foo<T>> getFoos(String bar);
}

Let's further assume there will be many different concrete implementations of FooMaker. So I wrote some code to utilize the FooMakers.

FooMaker<?> maker = Foos.getRandomMaker();
List<Foo<?>> fooList = maker.getFoos("bar");  //error here!

The second line of code causes the issue, eclipse tells me the code should be:

FooMaker<?> maker = Foos.getRandomMaker();
List<?> fooList = maker.getFoos("bar");

I'm having trouble understanding why the Foo declaration as the parameterized type in List has to go away to make the return type correct.

Any ideas?

like image 626
Nick Avatar asked Nov 05 '22 07:11

Nick


1 Answers

Try this instead:

List<? extends Foo<? extends Enum<?>>> fooList = maker.getFoos("bar");

The problem is that if this has been allowed:

List<Foo<?>> fooList = maker.getFoos("bar");

Then by extension, you would've been able to get away with this as well:

Foo<?> foo1 = new Foo<String>();
Foo<?> foo2 = new Foo<Integer>();
fooList.add(foo1);
fooList.add(foo2);

Which would invalidate the generic contract of the returned list.

To prevent this, the java compiler forces the return type to be wildcard-based, meaning Foo can be used as a return-type (to pull elements out of the list) but you will not be able to add wildcard-based Foo types to your list.

like image 184
Luke Hutteman Avatar answered Nov 11 '22 03:11

Luke Hutteman