Deciding between T super T and extends T
suggest changeThe syntax for Java generics bounded wildcards, representing the unknown type by ?
is:
? extends T
represents an upper bounded wildcard. The unknown type represents a type that must be a subtype of T, or type T itself.? super T
represents a lower bounded wildcard. The unknown type represents a type that must be a supertype of T, or type T itself.
As a rule of thumb, you should use
? extends T
if you only need “read” access (“input”)? super T
if you need “write” access (“output”)T
if you need both (“modify”)
Using extends
or super
is usually better because it makes your code more flexible (as in: allowing the use of subtypes and supertypes), as you will see below.
class Shoe {} class IPhone {} interface Fruit {} class Apple implements Fruit {} class Banana implements Fruit {} class GrannySmith extends Apple {} public class FruitHelper { public void eatAll(Collection<? extends Fruit> fruits) {} public void addApple(Collection<? super Apple> apples) {} }
The compiler will now be able to detect certain bad usage:
public class GenericsTest { public static void main(String[] args){ FruitHelper fruitHelper = new FruitHelper() ; List<Fruit> fruits = new ArrayList<Fruit>(); fruits.add(new Apple()); // Allowed, as Apple is a Fruit fruits.add(new Banana()); // Allowed, as Banana is a Fruit fruitHelper.addApple(fruits); // Allowed, as "Fruit super Apple" fruitHelper.eatAll(fruits); // Allowed Collection<Banana> bananas = new ArrayList<>(); bananas.add(new Banana()); // Allowed //fruitHelper.addApple(bananas); // Compile error: may only contain Bananas! fruitHelper.eatAll(bananas); // Allowed, as all Bananas are Fruits Collection<Apple> apples = new ArrayList<>(); fruitHelper.addApple(apples); // Allowed apples.add(new GrannySmith()); // Allowed, as this is an Apple fruitHelper.eatAll(apples); // Allowed, as all Apples are Fruits. Collection<GrannySmith> grannySmithApples = new ArrayList<>(); fruitHelper.addApple(grannySmithApples); //Compile error: Not allowed. // GrannySmith is not a supertype of Apple apples.add(new GrannySmith()); //Still allowed, GrannySmith is an Apple fruitHelper.eatAll(grannySmithApples);//Still allowed, GrannySmith is a Fruit Collection<Object> objects = new ArrayList<>(); fruitHelper.addApple(objects); // Allowed, as Object super Apple objects.add(new Shoe()); // Not a fruit objects.add(new IPhone()); // Not a fruit //fruitHelper.eatAll(objects); // Compile error: may contain a Shoe, too! }
Choosing the right T
, ? super T
or ? extends T
is necessary to allow the use with subtypes. The compiler can then ensure type safety; you should not need to cast (which is not type safe, and may cause programming errors) if you use them properly.
If it is not easy to understand, please remember PECS rule:
Producer uses “Extends” and Consumer uses “Super”.
(Producer has only write access, and Consumer has only read access)
Found a mistake? Have a question or improvement idea?
Let me know.
Table Of Contents