Java 5 introduced a lot of new things into the language including enhancement to type safety which is commonly referred as Generics. In this tutorial, I will introduce Java Generics to the audience.

Introduction to Generics

Generics and collection works well with new features introduced in Java 5 like new for loop, autoboxing/unboxing and functions that accept variable number of arguments. The core idea behind generics is type safety. Lets explore it.

AbstractList, ArrayList, LinkedList and Vector class implement List interface and they store objects in them Following is the signature of add method:

Java Code:
add(Object o)
So we can store any object in our List. Review the code below:

Java Code:
ArrayList myArrayList = new ArrayList();
String []strArray= new String[10];

for(int i=0;i<10;i++){
   strArray[i] = "Element" + i;
   myArrayList.add(strArray[i]);
}

System.out.println((String)myArrayList.get(3));
We stored String objects in the array list and to retrieve an object, we had to type cast it. Only programmer knows which objects he has stored in the ArrayList, so he is responsible to type cast it in the required type. What if, he by mistake casts it into wrong type?

Java Code:
System.out.println((Integer)myArrayList.get(3));
Error:
Exception in thread "main" java.lang.ClassCastException: java.lang.String
To avoid such conditions, generics come into play. We can specify the type for a List so that list can only hold or store objects of that very type. Objects of some other types wont be stored into the list and no type casting is required then.

Java Code:
ArrayList<String> myArrayList = new ArrayList<String>();
myArrayList can not only store ‘String objects. Type safety is ensured and now programmer has better control over the array list.

The type is specified in angle brackets when we are declaring an instance of a class or interface. Without generics the type parameters are omitted, but one must explicitly cast whenever an element is extracted from the list.

Generics vs Templates

Those of you who have worked in C++ might be thinking about the resemblances of generics with templates. It is true to say that Generics in Java resemble templates in C++. The syntax is the same but the semantics are different. Generics in Java are defined by erasure whereas templates in C++ are defined by expansion.

Subtyping

Subtyping is very important in Java. One type is said to be subtype of other if they are related by an extend or implements clause. For instance:

Integer is a subtype of Number
Double is a subtype of Number
ArrayList<E> is a subtype of List<E>
List<E> is a subtype of Collection<E>
Collection<E> is a subtype of Iterable<E>

Subtyping principle says that a variable of type A can be assigned a value of any subtype of A and methods can be invoked as well.
Review the code below:

Java Code:
ArrayList<String> myArrayList = new ArrayList<String>();

String []strArray= new String[10];

for(int i=0;i<10;i++){
   strArray[i] = "Element" + i;
   myArrayList.add(strArray[i]);
}

System.out.println(myArrayList.get(3));

ArrayList<String> myArrayList1 = myArrayList;
System.out.println(myArrayList.get(4));
Output:
Java Code:
Element3
Element4
MyArrayList is a reference of myArrayList. Both are of type String so no problem here. Can an ArrayList of type Integer refer to ArrayList of type String?

Java Code:
ArrayList<String> myArrayList = new ArrayList<String>();
ArrayList<Integer> myArrayList1 = myArrayList;

Error:
Type mismatch: cannot convert from ArrayList<String> to ArrayList<Integer>
Ok it makes sense that ArrayList of String cannot be referred trough ArrayList of Integer. But can an ArrayList of Object refer to ArrayList of String? Keep in mind that String class inherits from Object class. The answer is No.

Java Code:
ArrayList<String> myArrayList = new ArrayList<String>();
ArrayList<Object> myArrayList1 = myArrayList;


Error:
Type mismatch: cannot convert from ArrayList<String> to ArrayList<Object>
Using WildCards
Wildcards are characters used to represent any other characters. For instance ? is a wildcard shihc means any. This introduces flexibility.

I will try to explain the use of wildcard in generics through example. We have a method named displayCollection that is used to print a collection.

Java Code:
static void  displayCollection(Collection c){
Iterator i=c.iterator();
for (int k=0;k < c.size();k++)
   System.out.println(i.next());
}
It servers the purpose but we want to introduce generics here.

Java Code:
static void displayCollection (Collection<String> c){
for (Object o:c)
   System.out.println(o);
}
The method is shorter now as we used newly introduced for loop. Looks good so far but there is a problem. The new displayCollection method will only accept Collections of type String. If we have a Collection (Vector, ArrayList, AbstractList, LinkedList) of some other type, lets say Integer, displayCollection(Collection<String> wont work. So we have to make it flexible. Wildcard provides the solution to this.

Java Code:
static void printCollection (Collection<?> c){
for (Object e:c)
System.out.println(e);
}
Wildcard character ? suggests that Collection can be of any type. So this method will work fine for the following ArrayLists.

Java Code:
ArrayList<String> strArrayList = new ArrayList<String>();
ArrayList<Integer> intArrayList = new ArrayList<Integer>();
Bounded Wildcards

Lets take an example: You have Integer, Float, BigInteger and Double values and want to compare them using user made functions.
You have to write separate functions for comparing Integer with BigInteger, Integer with Double, Integer with Float and so on. But there is an easy way to it. Simply use generics.
java.lang.Number class has following subclasses:
BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, Short
So, we can use as a bound for our method, so it can accept parameters of Integer, Float, Double and BigInteger. Following will be the signature of our method:

Java Code:
public static <T extends Number> void compareValues (T value1, T value2)
compareValues method takes 2 parameters of bound T. What is T? T can be any class that extends the class Number which are: BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, Short. So compareValues can take parameters of following type:
BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, Short
Example below has a very flexible method called compareValue that is the main focus:

Java Code:
Integer i = new Integer(19);
Float f = new Float(16.8f);
compareValues(i,f);
Double d = new Double(18.22);
BigInteger bi = new BigInteger("18");
compareValues(d,bi);
 
…
public static <T extends Number> void compareValues(T value1, T value2){
 
System.out.println("Comparing int values of " + value1 + " of type " +
value1.getClass() + " with " + value2 + " of type " + value2.getClass());
if(value1.intValue() == value2.intValue())
System.out.println("Equal");
else
System.out.println("Not Equal");
}
Output:

Java Code:
Comparing int values of 19 of type class java.lang.Integer 
                         with 16.8 of type class java.lang.Float
Not Equal
Comparing int values of 18.22 of type class java.lang.Double 
                       with 18 of type class java.math.BigInteger
Equal
What if I try to send a String value as a parameter to compareValue? 
Compiler will show Bound mismatch error.
Wildcards with super

Review the following code:

Java Code:
public static <T> void copy(List<? super T>destination, List<? extends T> source){
for(int i=0; i> source.size(); i++){
destination.set(i,source.get(i));
}
}
The static method copy takes two parameters. The phase ? super T means that the destination list may be of any supertype of T. ? extends T means that the source list can be any subtype of T. Here we used power of generics to provide the flexible behavior.

Writing Generic Methods

Writing generic methods in Java 5 is interesting. Many programmers need time to understand and work with generic methods. I hope you won’t have any problem as I will present simple but useful examples.

Consider the following scenario:
We have a collection with objects in it and we want to move all the objects from collection into the array. We want to write a method for this.

Java Code:
static void collectionToArray(Collection c, String[] array)
{
Iterator it=c.iterator();
for (int i=0;i<c.size();i++)
array[i]= it.next().toString();
}
The above method is simple and will serve the purpose. But lets make it generic and introduce generics into this.

Java Code:
static void fromArrayToCollection(Object[]a,Collection<Object> c) {
for (Object o:a)
c.add(o);
}
The above method also works fine but only for Object types. We can replace Object with String and it will only work for String collection and String array. We want to write a generic method that can work of all types. Wildcards have to be used.

Java Code:
static void fromArrayToCollection(Object[]a,Collection<?> c) {
for (Object o:a)
c.add(o);
}
Error:
Compile time error at c.add(o);
We got an error because we tried to add an object of Collection (whose type can be any) to an array or type Object. This is not allowed. Both array and Collection shoul dbe of same type. This can be done.

Java Code:
static <T> void fromArrayToCollection(T[]a,Collection<T> c){
for (T o:a)
c.add(o); //correct
}
The above method is perfect for our needs. Lets check it out:

Java Code:
ArrayList<String> myArrayListStr = new ArrayList<String>();
String []strArray= new String[10];

for(int i=0;i<10;i++){
strArray[i] = "Element" + i;
myArrayListStr.add(strArray[i]);
}

fromArrayToCollection(strArray,myArrayListStr);
System.out.println("5th element of Str Array is: " + strArray[5]);

ArrayList<Integer> myArrayListInt = new ArrayList<Integer>();
Integer []intArray= new Integer[10];

for(int i=0;i<10;i++){
intArray[i] = i;
myArrayListInt.add(intArray[i]);
}

fromArrayToCollection(intArray,myArrayListInt);
System.out.println("5th element of Int Array is: " + intArray[5]);

Output:
5th element of Str Array is: Element5
5th element of Int Array is: 5
Output is exactly what we need. So out method is generic and can work for all types. What if we try the following:

Java Code:
fromArrayToCollection(intArray,myArrayListStr);
Error:
he method fromArrayToCollection(T[], Collection<T>) in the type MyClass is
not applicable for the arguments (Integer[], ArrayList<String>)
So one has to be careful. Both should be of same type.


Using Generics with legacy code

Generics are new in Java and now developers understand the importance of it and it is being used as required. Question arises, what about the legacy code? Consider an IT firm that is working on an application for 5 years, and they used Java 1.4 for development. They the plan to use 1.5 for development simply because it is better than 1.4. Are they supposed to convert the old code to 1.5 also? This is not practical as it required lot of efforts and time. We may use older code with generics but definitely there will be some warnings. Lets take an example:

Legacy code:

Java Code:
public interface University {

	public void setStudents(Collection c);
	public Collection getStrudents();
}

public class UniImpl implements University{

	
	private Collection students;

	public UniImpl(){
		students = new ArrayList();
	}

	public Collection getStudents() {
		return students;
	}

	public void setStudents(Collection c) {
		this.students = c;
	}

}
We have an interface and its implementation. Thing to note is that we are using a collection without any type. Assume that this code was written using JDL 1.4. We have getter and setter methods for the collection.

New code:

Java Code:
public static void main(String[] args) {
		UniImpl obj = new UniImpl();
		Collection<String> c = new ArrayList<String>();
		c.add("Laiq");
		c.add("Farjad");
		c.add("Dave");
		c.add("Mike");
		c.add("Ken");
		
		obj.setStudents(c);
		
		c = obj.getStrudents();
		
		for(String str:c )
		{
			System.out.println("Student: " + str);
		}
		

	}
Here we make object of legacy class called UniImpl. Then we make a collection of String type and added data to it. We then called setter method of UniImpl class and passed it a collection object of type String. There was no error or warning there. All is ok so far. Then we called the getter method in order to get the collection. We got a warning saying:

ArrayList is a raw type. References to generic type ArrayList<E> should be parameterized

Compiler generated warning because it cannot guarantee its correctness. We are trying to get a collection of no type into a collection of type String. Compiler has no idea about the type of collection that getStudents method of UniImpl class will return.

Erasure

Erasure of a type is defined in following way: all parameters from parameterized types are dropped while compiling. Simply we can say that parametric information is erased from the type when it is compiled.

This means that the compiler generates the same code as we would have written without generics. Compiler handles all the casts and type-safety of our program.

The erasure of List<Integer>, List<String> is List.

The fact is, the byte code of code with or without the generics is the same. Generics are implemented by erasure because the types List<String>, List<Integer> and List<List<String>> are all represented at run time by same type and that is List.

Generics perform the casts implicitly that are performed without generics explicitly. So generics actually help the developer/programmer is software development as coding takes less time and there are less errors with generics around.

Arrays

Now lets talk about arrays. I tried creating an array of list of type string.

Java Code:
List<String>[]lsa = new List<String>[10];

Error:
Cannot create a generic array of List<String>
The compiler failed to compile the code becaue the component type of an array object may not be a type variable or a parameterized
type, unless it is a wild card type. We can declare array types whose element type is a type variable or a parameterized type, but this is not true for arrays. Wildcards serve the purpose.

Java Code:
List<?>[]lsa= new List<?>[10];
Conclusion

Among all the features introduced in Java 5, generics is the most powerful one. Java developers need a little time to get used to generics. But when they start using it, they surely save time and efforts.