Generics In Java
Generics
In Java, generics were introduced in J2SE 5 to deal with the type-safe objects. Before generics, we can store any type of objects in the collection, which is non-generic. Now, generics force to store the specific type of objects in Java.
Advantage of Generics
Type-safety- Generics holds only a single type of object. It doesn’t allow storing other types of objects.
Type casting is not required- There is no need to typecast the object in generics.
For example, before generics, we need to type cast.
- ArrayList al = new ArrayList();
- al.add("Java");
- String s = (String) al.get(0); //typecasting
Now, after generics, we don't need to typecast the object.
- ArrayList < String > al = new ArrayList < String > ();
- al.add("Java");
- String s = al.get(0);
Compile-Time Checking- Generics checked at the compile time. Thus, problem will not occur at the runtime.
For example.
- ArrayList < String > al = new ArrayList < String > ();
- al.add("Java");
- al.add(7); //Compile Time Error
Syntax
Class or Interface<Type>
Let’s see an example, given below, with ArrayList class.
Code
- import java.util.*;
- public class GenericsExample {
- public static void main(String args[]) {
- ArrayList < String > al = new ArrayList < String > ();
- al.add("Bob");
- al.add("Jack");
- String s = al.get(1);
- System.out.println("Element : " + s);
- Iterator < String > i = al.iterator();
- while (i.hasNext()) {
- System.out.println(i.next());
- }
- }
- }
Output
In the example, shown above, we are using the ArrayList class, but we can use any collection class in generics and we can observe that there is no need of type casting.
Let’s see an example: with Map, given below.
Code
- import java.util.*;
- public class GenericsExample {
- public static void main(String args[]) {
- Map < Integer, String > m = new HashMap < Integer, String > ();
- m.put(19, "Bunny");
- m.put(45, "Harry");
- m.put(63, "Jack");
- Set < Map.Entry < Integer, String >> s = m.entrySet();
- Iterator < Map.Entry < Integer, String >> i = s.iterator();
- while (i.hasNext()) {
- Map.Entry e = i.next();
- System.out.println(e.getKey() + " " + e.getValue());
- }
- }
- }
Output
In the example, mentioned above, we use map elements, using generics. Now, we need to pass the key and value and we can observe that there is no need of type casting.
Generic class
A generic class can refer to any type. Now, we are using T type parameter to create the generic class of specific type.
Let’s see an example: Creating generic class
Code
- public class Gen < T > {
- T t;
- void add(T t) {
- this.t = t;
- }
- Tget() {
- return t;
- }
- }
The T type point to that it can refer to any type (like String, Integer, Student etc.). The type we specify for the class and it will be used to store and retrieve the data.
Let’s see the program to use the generic class.
Code
- public class GenericsExample {
- public static void main(String args[]) {
- Gen < Integer > m = new Gen < Integer > ();
- m.add(25269);
- System.out.println(m.get());
- }
- }
Output
Important type Parameters
T - Type
E - Element
K - Key
N - Number
V - Value
Generic Method
As same as generic class, we can create generic method that can accept any type of argument.
Let’s see an example.
Code
- public class GenericsExample {
- public static < E> void printArray(E[] elements) {
- for (E e : elements) {
- System.out.println(e);
- }
- System.out.println();
- }
- public static void main(String args[]) {
- Integer[] iArr = {1, 2, 3};
- Character[] cArr = {'H', 'A', 'R', 'R', 'Y'};
- System.out.println(" Int Array");
- printArray(iArr);
- System.out.println(" Char Array");
- printArray(cArr);
- }
- }
Output
In the above example, Generic method to print array elements and we are using E to denote the element.
Wildcard in Generics
The question mark (?) symbol signify wildcard element in generics that means any type. For example: If we write <? extends Number> it means any child class of Number like Integer, Float, double etc. Now, we can call the method of Number class by any child class object.
Let’s see an example.
Code
- import java.util.*;
- abstract class Animal {
- abstract void eat();
- }
- class Dog extends Animal {
- void eat() {
- System.out.println("Dog eat non-veg..");
- }
- }
- class Cat extends Animal {
- void eat() {
- System.out.println("Cat eat veg..");
- }
- }
- public class GenericsExample {
- public static void animalEat(List << ? extends Animal > lists) {
- for (Animal a: lists) {
- a.eat();
- }
- }
- public static void main(String args[]) {
- List < Dog > al = new ArrayList < Dog > ();
- al.add(new Dog());
- List < Cat > al1 = new ArrayList < Cat > ();
- al1.add(new Cat());
- al1.add(new Cat());
- animalEat(al);
- animalEat(al1);
- }
- }
Output
Summary
Thus, we learned that Generics force to store the specific type of objects in Java and also learn its advantages in Java.