For your example, you can use a plain List
like Dan and Paul said; you don't need to use the wildcard question mark syntax such as List super Shape>
or List extends Shape>
). I think your underlying question may be, "when would I use one of the question mark style declarations?" (The Get and Put Principle that Julien cites is a great answer to this question, but I don't think it makes much sense unless you see it in the context of an example.) Here's my take at an expanded version of the Get and Put Principle for when to use wildcards.
Use extends T>
if...
- A method has a generic class
parameter
Foo
readSource
- The method GETS instances of T from readSource, and doesn't care if the actual object retrieved belongs to a subclass of T.
Use super T>
if...
- A method has a generic class parameter
Foo
writeDest
- The method PUTS instances of T into writeDest, and doesn't care if writeDest also contains objects that are subclasses of T.
Here's a walkthrough of a specific example that illustrates the thinking behind wildcards. Imagine you are writing a processSquare method that removes a square from a list, processes it, and stores the result in an output list. Here's a method signature:
void processSquare(List iSqua, List oSqua)
{ Square s = iSqua.remove(0); s.doSquare(); oSqua.add(s); }
Now you create a list of DoubleSquares, which extend Square, and try to process them:
List dsqares = ...
List processed = new ArrayList;
processSquare(dsqares, processed); // compiler error! dsquares is not List
The compiler fails with an error because the type of dsquares List
doesn't match the type of the first parameter to processSquare, List
. Perhaps a DoubleSquare is-a Square, but you need to tell the compiler that a List
is-a List
for the purposes of your processSquare method. Use the extends Square>
wildcard to tell the compiler that your method can take a List of any subclass of Square.
void processSquare(List extends Square> iSqua, List oSqua)
Next you improve the application to process Circles as well as Squares. You want to aggregate all your processed shapes in a single list that includes both circles and squares, so you changed the type of the processed list from a List
to a List
:
List dsqares = ...
List circles = ...
List processed = new ArrayList;
processSquare(dsqares, processed); // compiler error! processed is not List
The compiler fails with a new error. Now the type of the processed list List
doesn't match the 2nd parameter to processSquare, List
. Use the super Square>
wildcard to tell the compiler that a given parameter can be a List of any superclass of Square.
void processSquare(List extends Square> iSqua,
List super Square> oSqua)
Here's the full source code for the example. Sometimes I find it easier to learn stuff by starting with a working example and then breaking it to see how the compiler reacts.
package wild;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public abstract class Main {
// In processing the square,
// I'll take for input any type of List that can PRODUCE (read) squares.
// I'll take for output any type of List that can ACCEPT (write) squares.
static void processSquare(List extends Square> iSqua, List super Square> oSqua)
{ Square s = iSqua.remove(0); s.doSquare(); oSqua.add(s); }
static void processCircle(List extends Circle> iCirc, List super Circle> oCirc)
{ Circle c = iCirc.remove(0); c.doCircle(); oCirc.add(c); }
public static void main(String[] args) {
// Load some inputs
List circles = makeList(new Circle());
List dsqares = makeList(new DoubleSquare());
// Collated storage for completed shapes
List processed = new ArrayList();
// Process the shapes
processSquare(dsqares, processed);
processCircle(circles, processed);
// Do post-processing
for (Shape s : processed)
s.shapeDone();
}
static class Shape { void shapeDone() { System.out.println("Done with shape."); } }
static class Square extends Shape { void doSquare() { System.out.println("Square!"); } }
static class DoubleSquare extends Square {}
static class Circle extends Shape { void doCircle() { System.out.println("Circle!"); } }
static List makeList(T a) {
List list = new LinkedList(); list.add(a); return list;
}
}