Site Search:

Wildcards

<Back

beat them all wildcards
beat them all wildcards

Syntax:

A wildcard generic type is an unknown generic type represented with a question mark. 
Unbounded wildcard (?) syntax is illustrated in the following example, it represents any class/interface type.

List<?> list = new ArrayList<Integer>();
List<?> list = new LinkedList<RuntimeException>();
List<?> list = new CopyOnWriteArrayList<Map<String, Integer>>();

Lower Bounded Wildcard (? extends type) represents any type which is a subclass of type.

Set<? extends Exception> set = new HashSet<Object>();     //not compile
Set<? extends Exception> set = new HashSet<Throwable>();  //not compile
Set<? extends Exception> set = new HashSet<Exception>();
Set<? extends Exception> set = new TreeSet<RunTimeException>();
Set<? extends Exception> set = new LinkedHashSet<ArithmeticException>();
Set<? extends Exception> set = new CopyOnWriteArraySet<IOException>();

Upper Bounded Wildcard (? super type) represents any type which is a superclass of type.

Queue<? super IOException> queue = new LinkedList<FileNotFoundException>();  //not compile
Queue<? super IOException> queue = new LinkedList<IOException>(); 
Queue<? super IOException> queue = new PriorityQueue<Exception>();
Queue<? super IOException> queue = new LinkedBlockingQueue<Throwable>();
Queue<? super IOException> queue = new ArrayBlockingQueue<Object>(10);

Fundamental problem

scorates forms
scorates forms

In java syntax, if A is a subclass of B, Box<A> is not a subclass of Box<B>.

For example, in the language of java inheritance, even though A is a B, a collection of A is not a collection of B. Don't ask me why, leave that to philosophers, Socrates can easily argue with you.

OCPJP pro: a basket of apple is a basket of fruit, that is all natural.
Socrates: an apple is a fruit, a basket can hold an apple, but no basket can hold the form of apples, which is fruit. Only the form of baskets can hold the form of apples.
OCPJP pro: ...
Socrates: besides, a person is a food (of tiger), does that mean a group of persons is a group of food (of tiger)?
OCPJP pro: ..., I'd better think less and practice more on the java generic syntax.

OCPJP Test Points

The wildcards syntax is simple in the scope of OCPJP, but the testers can play tons of tricks there. Let's approach the solution like elementary school algebra -- remember a list of rules, then use them to solve problems.
  • A extends B or A implements B doesn't mean Collection<A> extends Collection<B> or Collection<A> implements Collection<B>
OCPJP>cat Swimmers.java 
import java.util.*;
interface Swimmer {void swim();}
class Fish implements Swimmer {public void swim(){}}
class Student implements Swimmer{public void swim(){}}
public class Swimmers {
  private static int countSwimmers(List<Swimmer> list) {return list.size();}
  private static int countSpecificSwimmers(List<? extends Swimmer> list) { return list.size();}
  public static void main(String[] args) {
    List<Fish> fishes = new ArrayList<>();
    fishes.add(new Fish());
    fishes.add(new Fish());
    List<Student> students = new ArrayList<>();
    students.add(new Student());

    List<Swimmer> swimmers = new ArrayList<>();
    swimmers.addAll(fishes);
    swimmers.addAll(students);

    //System.out.println(countSwimmers(fishes));  //List<Fish> cannot be converted to List<Swimmer>
    //System.out.println(countSwimmers(students));  //List<Student> cannot be converted to List<Swimmer>
    System.out.println(countSwimmers(swimmers));

    System.out.println(countSpecificSwimmers(fishes));
    System.out.println(countSpecificSwimmers(students));
    System.out.println(countSpecificSwimmers(swimmers));
  }
}

OCPJP>java Swimmers
3
2
1
3
OCPJP>
  • You can pass a Collection of anything to Collection<?> but not to Collection<Object>
OCPJP>cat ObjWild.java
import java.util.*;
public class ObjWild{
  public static void objPrint(Collection<Object> list) {
    System.out.println("objPrint" + list.size());
  }
  public static void wildPrint(Collection<?> list) {
    System.out.println("wildPrint" + list.size());
    for(Object obj: list) {
      System.out.println(obj);
    }
  }
  public static <T>void unknownPrint(Collection<T> list) {
    System.out.println("unKnownPrint" + list.size());
    for(T t: list) {
      System.out.println(t);
    } 
  }
  public static void main(String[] args) {
    List<String> fruits = new ArrayList<>();
    fruits.add("apple");
    //objPrint(fruits);  //incompatible types: List<String> cannot be converted to Collection<Object>
    wildPrint(fruits);
    unknownPrint(fruits);
  }
}
OCPJP>javac ObjWild.java 
OCPJP>java ObjWild
wildPrint1
apple
unKnownPrint1
apple
OCPJP>
  • You can not modify the Collection declared with unbounded wildcards and upper bound wildcards.
import java.util.*;
public class Basket {
  static class Apple extends Fruit {}
  static class Fruit {}
  public static void main(String... args) {
    List<? extends Fruit> fruitBasket = new ArrayList<Apple>();
    fruitBasket.add(new Apple()); //no suitable method found for add(Apple)
    fruitBasket.add(new Fruit()); //no suitable method found for add(Fruit)
    fruitBasket = new ArrayList<Fruit>();
    fruitBasket.add(new Apple()); //no suitable method found for add(Apple)
    fruitBasket.add(new Fruit()); //no suitable method found for add(Fruit)
    List<?> container = new ArrayList<Apple>();
    container.add(new Apple());  //no suitable method found for add(Apple)
    container.add(new Fruit());  //no suitable method found for add(Fruit)
    container = new ArrayList<Fruit>();
    container.add(new Apple());  //no suitable method found for add(Apple)
    container.add(new Fruit());  //no suitable method found for add(Fruit)
  }
}

  • You can add elements to Collection declared with lower bound wildcards. The added elements have to be subclass of the lower bound class.
OCPJP>cat SuperConfusing.java 
import java.util.*;
import java.io.*;
import java.util.concurrent.*;
public class SuperConfusing {
  public static void main(String args[]) {
    //Queue<? super IOException> queue = new LinkedList<FileNotFoundException>();  //not compile
    Queue<? super IOException> queue = new LinkedList<IOException>(); 
    //queue.add(new Object());  //no suitable method found for add(Object) 
    //queue.add(new Throwable());  //no suitable method found for add(Throwable) 
    //queue.add(new Exception());  //no suitable method found for add(Exception) 
    queue.add(new IOException());  
    queue.add(new FileNotFoundException());

    queue = new PriorityQueue<Exception>();
    //queue.add(new Object());  //no suitable method found for add(Object) 
    //queue.add(new Throwable());  //no suitable method found for add(Throwable) 
    //queue.add(new Exception());  //no suitable method found for add(Exception) 
    queue.add(new IOException());  
    queue.add(new FileNotFoundException());

    queue = new LinkedBlockingQueue<Throwable>();
    //queue.add(new Object());  //no suitable method found for add(Object) 
    //queue.add(new Throwable());  //no suitable method found for add(Throwable) 
    //queue.add(new Exception());  //no suitable method found for add(Exception) 
    queue.add(new IOException());  
    queue.add(new FileNotFoundException());

    queue = new ArrayBlockingQueue<Object>(10);
    //queue.add(new Object());  //no suitable method found for add(Object) 
    //queue.add(new Throwable());  //no suitable method found for add(Throwable) 
    //queue.add(new Exception());  //no suitable method found for add(Exception) 
    queue.add(new IOException());  
    queue.add(new FileNotFoundException());
  }
}
OCPJP>javac SuperConfusing.java 
OCPJP>java SuperConfusing
Exception in thread "main" java.lang.ClassCastException: java.io.FileNotFoundException cannot be cast to java.lang.Comparable
at java.util.PriorityQueue.siftUpComparable(PriorityQueue.java:652)
at java.util.PriorityQueue.siftUp(PriorityQueue.java:647)
at java.util.PriorityQueue.offer(PriorityQueue.java:344)
at java.util.PriorityQueue.add(PriorityQueue.java:321)
at SuperConfusing.main(SuperConfusing.java:19)

In the above example, the code compiles, the runtime exception is due to PriorityQueue internal. It expects a Comparable. We dismiss it as a distraction from the current topic.
  • Watch out OCPJP tricks: replace "?" with specific type in the method parameter, put wildcards in the method return type.
The following declaration syntax in OCPJP are common traps.
  1. <T> void aMethod(List<T super Exception> list) {}
  2. <T> void aMethod(List<T extends Exception> list) {}
  3. <T, U> T aMethod(List<U extends T> list) {return list.get(0);} 
  4. <T, U> T aMethod(List<U super T> list) {return list.get(0);}
  5. <T> <? extends T> aMethod(List<? extends T> list) {return list.get(0);} 
  6. <T> <? extends T> aMethod(List<? super T> list) {return list.get(0);} 
  7. <T> <? extends T> aMethod(List<?> list) {return list.get(0);}
  8. <T> <? super T> aMethod(List<?> list) {return list.get(0);}

The fixing are:
  1. <T> void aMethod(List<? super Exception> list) {}
  2. <T> void aMethod(List<? extends Exception> list) {}
  3. <T, U> T aMethod(List<? extends T> list) {return list.get(0);}
  4. <T, U> Object aMethod(List<? super T> list) {return list.get(0);}
  5. <T> T aMethod(List<? extends T> list) {return list.get(0);} 
  6. <T> Object aMethod(List<? super T> list) {return list.get(0);} 
  7. <T> Object aMethod(List<?> list) {return list.get(0);}
  8. <T> Object aMethod(List<?> list) {return list.get(0);}