Sunday, March 2, 2014

Generics - Java

Generics

The main concept of Generics is to define typed variables and make the compiler to pre-check the types v/s values before actual execution of the program. So, in short, Generic type is a class or an interface which can be parameters for type. 

How to define

Generic is defined by using an angular brace like <T>.
Syntax:
class name<T1,T2,.... >
Example:
List<String> list = new ArrayList<String>();
Most of the classes (In fact all) of Collections are generic. So, when you look at the method of List class.
boolean add(E e);
E could be any type that you have defined while creating the instance of the List.

Points to be noted

So, there are couple of points to be noted before getting into the details of the generics.

What types:

Instead of looking for what types are allowed lets look at what types are not allowed because all types are allowed expect for primitives ;) 

How many:

There is no limit for the number of types that can be defined. We can define any number of types.

Where to define:

Generics can be defined for
  • Classes
  • Interfaces
  • Constructors
  • Methods

Uses

  • Introduce strong types for the custom classes, collections
  • Remove the explicit casting of objects.
  • Autoboxing / Autounboxing features can be used directly with generics.
  • Wildcards works (? extends and ? super)with generics which made the hierarchy typing as easy.

Explanation

Let's see the uses with an example for each

Strong Types and Casting

Let's define a List.
//Normal 
List oList = new ArrayList();

//Generic type
List<String> gList = new ArrayList<String>();
Here
  • aList - can store any type of element in list object and developer has to be careful enough while reading and writing into it. 
  • gList - can store only String types and compiler throws error while writing elements into it other than Strings.

Reading:
aList.add("name"); //Allowed
aList.add(1); //Allowed

gList.add("name"); //Allowed
gList.add(1) //Now allowed
Writing:
//aList operations
String str = (String)aList.get(0); //Requires explicit casting
Integer aInt = (Integer)aList.get(1); //Requires explicit casting

Integer incorrect = (Integer)aList.get(0); //No compilation error but throws runtime exception.

//gList operations
String a = gList.get(0) //No explicit casting.

Integer b = gList.get(1) //Not allowed. Compiler throws error. but still you can explicitly convert it to Integer.
Iterating:
//Using iterator
for (Iterator iter = gList.iterator(); iter.hasNext();) {
  String s = iter.next();
  System.out.print(s);
}

//Using foreach
for (String s: gList) {
   System.out.print(s);
}

Autoboxing / Autounboxing

We can define generics for any type expect for built-in types but autoboxing and unboxing works with generics like below without any issues.
//Autoboxing
Set set = new HashSet();
set.add(1);
set.add(3);

//Autounboxing
for(int s : set)
{
  System.out.println(s);
}

Wildcards

Even if we define a class with generic types, sometimes we may need to use them based on the hierarchy. It can be either a subclass declaration or super class declaration. The keywords for the wildcards used are
  • ? extends T - Any class which extends T
  • ? super T - Any class which is super to T
void eat(List<? extends Fruit> fruits); //This method accepts parameter any list of objects which is child of Fruit
void eat(List<? super Fruit> fruits); //This method accepts parameter any list of objects which is parent of Fruit 
Happy Learning!!!!