Monday, June 2, 2014

Wildcard in Generics

Generics is confusing (in fact one of the most confusing concepts of Java); and on top of it, wildcards (bounds) is even more confusing. That explains, the reason for this dedicated post :)
In the Generics post; I discussed that subtyping doesn't work with Generics. So, If Apple extends Fruit; list of Apple is not a subtype of list of Fruit. Does it mean that Generics can't be generic and you can't write a method which work for subtype? Luckily, wildcard helps you make Generics really generic.

Bounded Wildcard

Generics uses a wildcard character (?) to work with subtype. Let's go in detail on each.

upper-bounded wildcard: uses wildcard(?), followed by extends keyword, followed by its upper bound. 
List<? extends Number> will work for List of Number and list of its subtype (Integer, Double and Float).

List<Integer> li = new ArrayList<Integer>();
List<? extends Number> list = li;

lower-bounded wildcard: uses wildcard, followed by super keyword, followed by its lower bound. 
List<? super Integer> will work for list of Integer, list of Number and list of Object.

List<Number> ln = new ArrayList<Number>();
List<? super Integer> list1=ln;

Unbounded Wildcard

Using just the wildcard i.e. ? makes it unbounded. It means anything, so equivalent to using raw type. 
<?> says that; i wrote code keeping in mind Generics, but it can hold any type. 

List<?> is a non raw list of some specific type but we don't know what the type is. You can't pass any type. So the type is unknown but it doesn't mean that it can take any shit!

List<Integer> li2 = new ArrayList<Integer>();
List<?> l3 = li2;

 

Code Talk

Time to walk the talk through a simple example.

import java.util.ArrayList;
import java.util.List;

/**
 * Defines Base class Fruit and sub classes Apple and FujiApple. 
 * Uses BoundsGenericsTest for testing wildcard.
 * Save it as BoundsGenericsTest.java
 * 
 * @author Siddheshwar
 * 
 */
class Fruit {
 protected String name;

 public Fruit(String name) {
  super();
  this.name = name;
 }

 public String toString() {
  return name;
 }
}

class Apple extends Fruit {
 public Apple(String name) {
  super(name);
 }
}

class FujiApple extends Apple {
 public FujiApple(String name) {
  super(name);
 }
}

public class BoundsGenericsTest {
 List<? extends Fruit> list;

 public void add(List<? extends Fruit> f) {
  list = f;
 }

 public static void main(String[] args) {
  BoundsGenericsTest obj = new BoundsGenericsTest();

  List<Apple> apples = new ArrayList<Apple>();
  apples.add(new Apple("apple1"));
  apples.add(new Apple("apple2"));

  obj.add(apples);
  System.out.println(" list of Apples: " + obj.list);

  List<FujiApple> fujiApples = new ArrayList<FujiApple>();
  fujiApples.add(new FujiApple("fujiapple1"));
  fujiApples.add(new FujiApple("fujiapple2"));
  obj.add(fujiApples);
  System.out.println(" list of FujiApples : " + obj.list);

  List<? super FujiApple> another = 
                            (List<? super FujiApple>) obj.list;
  System.out.println(" val :" + another);
  List<? super FujiApple> another1 = fujiApples;
  System.out.println(" val :" + another);

  //unbounded wildcard
  List<?> fruits = apples;
  System.out.println("Fruits:" + fruits);
 }
}

Output:
 list of Apples: [apple1, apple2]
 list of FujiApples : [fujiapple1, fujiapple2]
 val :[fujiapple1, fujiapple2]
 val :[fujiapple1, fujiapple2]
Fruits:[apple1, apple2]

Related Post : Java Generics

No comments:

Post a Comment