Generics in JAVA
By: Rony Emrul
Tags: Java, Generics, Object Oriented

Generics is one of the most important and hard to wrap head around features of the Java programming language. It was introduced in Java 1.5 version.

What is Generics?

Generally, a java class can take any type of Object. With generic, we can make a java Class, Interface, and method type-specific.

Benefits of Generics

Generics provide type safety With Generics, we don’t need to perform type casting It provides reusability of our code

Let’s see how it helps us to make our code type-safe.

We can store any type of object in collections. At the time of retrieving it may lead to ClassCastException or incompatible types Error.

The above code will lead to ClassCastException and Incompatible Type Error .

Now applying Generics we can force the ArrayList to take only a specific type of object so that we don't need to typecast anymore and ClassCastException will not occur.

We can use any object as a type for Generic but can’t use any primitive value.

Collection framework before and after Java 1.5

Before Generics (till Java 1.4) ArrayList class defined like this

class ArrayList{

add (Object o){...};

Object get(int index){...};

}

The argument to the add() is an object. So we can insert any type of Object.

The return type of get() method is Object. So at the time of retrieval, we have to perform typecasting.

After Java 1.5 the Generic version of ArrayList looks like this

class ArrayList<T>{

add(T t){...};

T get(int index){...};

}

At runtime type parameter ‘T’ will be replaced with the corresponding provided type.

For, ArrayList<String> obj = new ArrayList<String> following populated version of code will be generated at runtime.

class ArrayList<String>{

add(String s){...};

String get(int index){...};

}

Since the add() method takes String as a parameter so we can add only String object to the ArrayList.

method takes String as a parameter so we can add only String object to the ArrayList. The return type of the get() is String so we get only String object at the time of retrieval.

Java generic type parameter

Here is the naming convention provided by Java that helps you to understand the Java Generic. The most used type parameter names are:

E — Element (Used in Collections Framework for example Set)

K — Key (Used in Collections Framework for example Map)

N — Number

T — Type

V — Value (Used in Collections Framework for Map)

Custom Generic Class

We can make a class a Generic class by making it refer to any type (Integer, String, Character, Student, Object, etc.)

Below is an example of a Generic class

Output:

Type of the class: java.lang.Integer

Type of the class: java.lang.String

Type of the class: java.lang.Boolean

Custom generic class with multiple type parameter

Output:

100

Emrul

Wildcard in Generics (?)

The question mark (?) is known as wildcard

Wildcard represents an unknown type

The use of wildcard is to control the type safety of the generic type.

It restricts the unknown type to be specific.

Wildcard also describes a family of type

Three types of wildcards in Java

Unbounded wildcard <?> Upper bounded type “<? extends Type>” Lower bounded type “<? super Type>”

Unbounded type < ? >

It stands for the family of all types. That means while printCollection(List<Integer> list) method can accept only Integer type list as an argument, printCollection(List<?> list) can accept Integer, String, Boolean, Object, Student, etc. (basically all subclasses of Object) type list as an argument.

Output:

chandler bing ross geller

2 4 6 8 10

Monica 30 true

Upper bounded type “<? extends Type>”

Describes the family of all types that are a subtype of ‘Type’, including the type ‘Type’.

For example in printCollection(Collection<? extends Number> value) method, only those types of Collection objects can be passed as an argument who are either Number type or subtypes of Number like Integer, Double, Float. This type of wild card is used for reading purpose when object type is partially known.

Since we don’t know the actual runtime object type, we can’t perform add operation to a collection object using unbounded and upper bounded generic wildcard. We can only perform read operation.

Lower bounded type “ <? super Type> “

Describes the family of all types that are the supertype of ‘Type’, including the type ‘Type’.

In addToCollection(Collection<? super Integer> value) method only those types of objects of Collection can be passed who are either Integer type of supertype of Integer like Number , Object . Lower bounded wildcards are mostly used for reading purpose.

Generic Methods

Generic methods are methods that introduce their own type parameters. This is similar to declaring a generic type, but the type parameter’s scope is limited to the method where it is declared.

Suppose, we want to write a method that takes an array and collection object and add the elements of the array into the collection.

static void fromArrayToCollection(Object[] arr, Collection<?> coll){ for (Object obj : arr){

coll.add(obj); // compile time error

}

}

Since we can’t add objects to unknown types the above code will give us a compile time error.

The way to do deal with these problems is to use generic methods. Just like type declarations, method declarations can be generic — that is, parameterized by one or more type parameters.

static <T> void fromArrayToCollection(T[] a, Collection<T> c) {

for (T o : a) {

c.add(o); // Correct

}

}

Full example code,

We can also use multiple type parameter in a generic method just like the example below,