How can elements be added to a wildcard generic collection?

Tags: generics java
Question!

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.



Answers

Just thought I'd add to this old thread, by summarising the properties of List parameters instantiated with types or wildcards....

When a method has a parameter/result which is a List, the use of type instantiation or wildcards determines

  1. Types of List which can be passed to the method as an argument
  2. Types of List which can be populated from the method result
  3. Types of elements which can be written to list within the method
  4. Types which can be populated when reading elements from list within the method

Param/Return type: List< Foo>

  1. Types of List which can be passed to the method as an argument:
    • List< Foo>
  2. Types of List which can be populated from the method result:
    • List< Foo>
    • List< ? super Foo>
    • List< ? super SubFoo>
    • List< ? extends Foo>
    • List< ? extends SuperFoo>
  3. Types of elements which can be written to list within the method:
    • Foo & subtypes
  4. Types which can be populated when reading elements from list within the method:
    • Foo & supertypes (up to Object)

Param/Return type: List< ? extends Foo>

  1. Types of List which can be passed to the method as an argument:
    • List< Foo>
    • List< Subfoo>
    • List< SubSubFoo>
    • List< ? extends Foo>
    • List< ? extends SubFoo>
    • List< ? extends SubSubFoo>
  2. Types of List which can be populated from the method result:
    • List< ? extends Foo>
    • List< ? extends SuperFoo>
    • List< ? extends SuperSuperFoo>
  3. Types of elements which can be written to list within the method:
    • None! Not possible to add.
  4. Types which can be populated when reading elements from list within the method:
    • Foo & supertypes (up to Object)

Param/Return type: List<? super Foo>

  1. Types of List which can be passed to the method as an argument:
    • List< Foo>
    • List< Superfoo>
    • List< SuperSuperFoo>
    • List< ? super Foo>
    • List< ? super SuperFoo>
    • List< ? super SuperSuperFoo>
  2. Types of List which can be populated from the method result:
    • List< ? super Foo>
    • List< ? super SubFoo>
    • List< ? super SubSubFoo>
  3. Types of elements which can be written to list within the method:
    • Foo & supertypes
  4. Types which can be populated when reading elements from list within the method:
    • Foo & supertypes (up to Object)

Interpretation/Comment

  • needs of external callers drive the design of the method declaration i.e. the public API (normally the primary consideration)
  • needs of internal method logic drive any additional decisions re actual data types declared and constructed internally (normally the secondary consideration)
  • use List<Foo> if caller code is always focused on manipulating the Foo class, as it maximises flexibility for both read and write
  • use List<? extends UpperMostFoo> if there could be many different types of caller, focused on manipulating a different class (not always Foo) and there is a single uppermost class in the Foo type hierarchy, and if the method is to internally write to the list and caller list manipulation is reading. Here the method may internally use List< UpperMostFoo> and add elements to it, before returning List< ? extends UpperMostFoo>
  • if there could be many different types of caller, focused on manipulating a different class (not always Foo) and if reading and writing to list is required and there is a single lowest class in the Foo type hierarchy, then it makes sense to use List< ? super LowerMostFoo>
By : Glen Best


To get an idea of how generics works check out this example:

    List<SubFoo> sfoo = new ArrayList<SubFoo>();
    List<Foo> foo;
    List<? extends Foo> tmp;

    tmp = sfoo;
    foo = (List<Foo>) tmp;

The thing is, that wasn't designed for local/member variables, but for function signatures, that's why it's so ass-backwards.

By : zslevi


This video can help you solving your question :)
By: admin