tags:

views:

998

answers:

4

Why do I get compiler errors with this Java code?

1  public List<? extends Foo> getFoos()
2  {
3    List<? extends Foo> foos = new ArrayList<? extends Foo>();
4    foos.add(new SubFoo());
5    return foos;
6  }

Where 'SubFoo' is a concrete class that implements Foo, and Foo is an interface.

Errors I get with this code:

  • On Line 3: "Cannot instantiate ArrayList<? extends Foo>"
  • On Line 4: "The method add(capture#1-of ? extends Foo) in the type List<capture#1-of ? extends Foo> is not applicable for the arguments (SubFoo)"

Update: Thanks to Jeff C, I can change Line 3 to say "new ArrayList<Foo>();". But I'm still having the issue with Line 4.

+2  A: 

This thread has a good discussion of this issue, near the bottom: http://forums.sun.com/thread.jspa?threadID=633704&amp;messageID=3675111

Jeff C
+7  A: 

Use this instead:

1  public List<? extends Foo> getFoos()
2  {
3    List<Foo> foos = new ArrayList<Foo>(); /* Or List<SubFoo> */
4    foos.add(new SubFoo());
5    return foos;
6  }

Once you declare foos as List<? extends Foo>, the compiler doesn't know that it's safe to add a SubFoo. What if an ArrayList<AltFoo> had been assigned to foos? That would be a valid assignment, but adding a SubFoo would pollute the collection.

erickson
+1  A: 

The following will work fine:

public List<? extends Foo> getFoos() {
 List<Foo> foos = new ArrayList<Foo>();
 foos.add(new SubFoo());
 return foos;
}
SCdF
+4  A: 

Try:

public List<Foo> getFoos() {
    List<Foo> foos = new ArrayList<Foo>();
    foos.add(new SubFoo());
    return foos;
}

The generic ArrayList constructor needs to have a specific type to be parameterized on, you cannot use the '?' wildcard there. Changing the instantiation to "new ArrayList<Foo>()' would solve the first compilation error.

The declaration of the 'foos' variable can have wildcards, but since you know the precise type, it makes more sense to reference the same type info there. What you have now says that foos holds some specific subtype of Foo, but we don't know which. Adding a SubFoo may not be allowed, since a SubFoo is not "all subtypes of Foo". Changing the declaration to 'List<Foo> foos = ' solves the second compilation error.

Finally, I would change the return type to 'List<Foo>' since clients of this method won't be able to do much with the returned value as currently defined. You should rarely use wildcards in return types. Use a parameterized method signature if needed, but prefer bounded types to only appear in method arguments, as that leaves it up to the caller who can pass in specific types and operate and them accordingly.