Generics

What ?

Generics is a feature provided by JAVA from JDK1.5 version.

The main purpose of the Generics is :

  1. To improve Type Safety in Collections.
  2. To resolve the Type casting problem in Collections

Type Safety in Collections

In General, when we represent the same type of elements, there type safety will come automatically, when we represent different types of elements there type safety will not come.

EX: Arrays are able to provide Type Safety, whereas Collections are not providing Type Safety, because in Java Arrays are able to represent the same type of elements , but Collections are able to represent heterogeneous elements.

In Java applications, to provide type safety in Collections we have to use generics.

EX:

String[] str = new String[3];
str[0] = “AAA”;
Str[1] = “BBB”;
Str[2] = “CCC”;
String str1 = str[0]; —-> Guarantee to get String value.

EX:

ArrayList al = new ArrayList();
al.add(“AAA”);
al.add(10);
al.add(22.22f);
String str = al.get(0); --> No Guarantee for String, where we must perform Type casting.
String str2 = (String)al.get(1); --> ClassCastException

Type Casting in Collections

In the case of Arrays, Type Casting is not required while retrieving elements from Arrays.

EX:

String[] str = new String[3];
str[0] = “AAA”;
Str[1] = “BBB”;
Str[2] = “CCC”;

String str1 = str[0];
String str2 = str[1];
String str3 = str[2];

In the case of Collections, to red elements we must perform Type Casting.

ArrayList al = new Arraylist();
al.add(“AAA”);
al.add(“BBB”);
al.add(“CCC”);

String str1 = (String)al.get(0);
String str2 = (String)al.get(1);
String str3 = (String)al.get(2);

In Collections , to retrieve the data without performing Typecasting we have to use Generics.

Syntax

To use Generics in Collections we have to provide Type Parameter along with Collection interfaces or Classes.

Syntax:

CollectionName<Type> refVar = new CollectionName<Type>();

ArrayList<String> al = new ArrayList<String>();
al.add(10); —-> Invalid
al.add(“ABC”); —---> Valid
al.add(22.22f); —----> Invalid

In the above Generic Declaration along with the Collection, Collection is able to allow only String type of elements, not allowing other types of elements, so Generics will improve Typed ness and it will provide Type Safety.

String str = al.get(0);
String str2 = al.get(1);

In the above Generic declaration along with the Collection , the type of elements inside the Collection are confirmed, so to retrieve elements from Collections no need to use typecasting.

Important points to consider

In Generics, at parameter types, polymorphism is not possible.

ArrayList<String> al = new ArrayList<String>(); —----> Valid
ArrayList<Number> al = new ArrayList<Integer>(); —---> Invalid
ArrayList<Object> al = new ArrayList<String>(); —----> Invalid

In Generics, Type Parameter must not be a Primitive Type, Type Parameter may be a class type and Interface Type.

ArrayList<String> al = new Arraylist<String>(); —---> Valid
ArrayList<int> al = new Arraylist<int>(); —-----> Invalid

1. We can use generics with interfaces.

2. We can use generics with classes.

3. If you have a generic class, you still can create a class without specifying any type.

→ The type that we use with generics, can be a predefined class or it can also be a user defined class.

Generic Classes

If we declare any class with the type parameter is called a Generic Class. You need to specify type <T> along with class name. Depending on the requirement we can pass any data type as Type Parameter.

class ClassName<T> {  
...
...
}

For the above Generic class, if we provide a particular type while creating an object then that objects are able to the respective type only.

EX:

Output :

Another example :

ArrayList class from JDK 1.5 version.

class ArrayList<T> {
add(T t) { }
T get(int index) { }
}

Depending on the requirement we can pass any data type as Type Parameter.

ArrayList<String> al = new ArrayList<String>();
al.add(“AAA”);
al.add(“BBB”);
al.add(10); —---> Error
String str1 = al.get(0);
String str2 = al.get(1);
ArrayList<Integer> al = new ArrayList<Integer>();
al.add(10);
al.add(20);
al.add(“AAA”);----> Error
int a = al.get(0);
int b = .get(1);

In Generic classes, we can pass more than one Type Parameter.

class HashMap<K,V> {   }

Custom Generic Class

In Java applications, we are able to provide our own generic classes.

class Gen<T> {
T t;
Gen(T t){
this.t=t;
}
void display(){
System.out.println(" Object Type : "+t.getClass().getName());
}
public T getObject(){
return t;
}
}
public class Main {
public static void main(String[] args) {
Gen<Integer> g1 = new Gen<Integer>(10);
g1.display();
System.out.println(g1.getObject());
System.out.println();

Gen<String> g2 = new Gen<String>("Durgasoft");
g2.display();
System.out.println(g2.getObject());
}
}

Bounded Types

In Generics, we can bound the Type parameter for a particular range by using either extends or super keyword.

Upper bounds

class Test<T extends X> 
{
...
...
}

If X is a class, then we can pass the type parameter to either the same class or subclasses.

If X is an interface then we can pass the type parameter either that interface or its implementation classes.

class Test<T extends Number> {
...
}
public class Main {
public static void main(String[] args) {
Test<Number> test1 = new Test<Number>();
Test<Integer> test2 = new Test<Integer>();
//Test<String> test3 = new Test<String>(); --> Error
}
}

In Generic classes, we can pass more than one Type Parameter.

class HashMap<K,V> {   }

In Generics, along with the extends keyword we can provide more than one bunded type.

class Test<T extends Number&Runnable>{  } —---> Valid

class Test<T extends Number&Runnable&Comparable>{ } —---> Valid

Wildcard characters

If we declare any method with a parameter that includes generic Type then that method is called a Generic Method.

? – wildcard type – is like data of any type.

void getDetails(ArrayList<?> al) {
al.add(null);
}

In the above wild character declaration , we can pass any data type.

In Generic Methods, it is possible to provide bounded types to the wild card characters.

import java.io.Serializable;
import java.util.ArrayList;

class Test {
void getDetails(ArrayList<? extends Number> al){
...
...
}
}
public class Main {
public static void main(String[] args) {
Test test = new Test();
//test.getDetails(new ArrayList<String>()); ---> Error
test.getDetails(new ArrayList<Number>());
test.getDetails(new ArrayList<Integer>());
}
}