Why do we need generics in Java?

As we know a class is a blue print in which we define the required behaviors and properties and, an interface is similar to class but it is a Specification (containing abstract methods).
These are also considered as datatypes in Java, unlike other primitive datatypes a literal of these kind of types points/refers to the location of the object. They are also known as reference types.
Generics is a concept in Java where you can enable a class, interface and, method, accept all (reference) types as parameters. In other words it is the concept which enables the users to choose the reference type that a method, constructor of a class accepts, dynamically.
By defining a class generic you are making it type-safe i.e. it can act up on any datatype. To understand generics let us consider an example −
In the following Java example we are defining a class named Student whose constructor (parameterized) accepts an Integer object. While instantiating this class you can pass an integer object
 Live Demo
class Student{
   Integer age;
   Student(Integer age){
      this.age = age;
   }
   public void display() {
      System.out.println("Value of age: "+this.age);
   }
}
public class GenericsExample {
   public static void main(String args[]) {
      Student std = new Student(25);
      std.display();
   }
}
Value of age: 25
Passing any other object to the constructor of this class generates a compile time exception
public static void main(String args[]) {
   Student std = new Student("25");
   std.display();
}
GenericsExample.java:12: error: incompatible types: String cannot be converted to Integer
   Student std = new Student("25");
                              ^
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
1 error
The age of a student could be passed as (an object of) String value, Float, Double etc. If you want to pass a value of another object you need to change the constructor as −
class Student{
   String age;
   Student(String age){
      this.age = age;
   }
}
Or,
class Student{
   Float age;
   Student(Float age){
      this.age = age;
   }
}
When you declare generic types they can act upon any datatypes and, they are known as parameterized types. You cannot use primitive datatypes in generics.
To create a class of generic type by using generic parameter T or, GT as −
class Student <T>{
   T obj;
}
Where T (generic parameter) represents the datatype of the object you can pass to the constructor of this class. This will be determined at the compilation time.
While instantiating the class you need to/can choose the type of the generic parameter as −
Student<Float> obj = new Student<Float>();
 Live Demo
We can rewrite the above example using generics as −
class Student<T>{
   T age;
   Student(T age){
      this.age = age;
   }
   public void display() {
      System.out.println("Value of age: "+this.age);
   }
}
public class GenericsExample {
   public static void main(String args[]) {
      Student<Float> std = new Student<Float>(25.5f);
      std.display();
   }
}
Value of age: 25.5
Now, while instantiating the Student class you can pass desired type of object as a parameter as −
class Student<T>{
   T age;
   Student(T age){
      this.age = age;
}
   public void display() {
      System.out.println("Value of age: "+this.age);
   }
}
public class GenericsExample {
   public static void main(String args[]) {
      Student<Float> std1 = new Student<Float>(25.5f);
      std1.display();
      Student<String> std2 = new Student<String>("25");
      std2.display();
      Student<Integer> std3 = new Student<Integer>(25);
      std3.display();
   }
}
Value of age: 25.5
Value of age: 25
Value of age: 25
Usage of generics in your code you will have the following advantages −
Type check at compile time −usually, when you use types (regular objects), when you pass an incorrect object as a parameter, it will prompt an error at the run time.
Type check at compile time −usually, when you use types (regular objects), when you pass an incorrect object as a parameter, it will prompt an error at the run time.
Whereas, when you use generics the error will be at the compile time which is easy to solve.
Whereas, when you use generics the error will be at the compile time which is easy to solve.
Code reuse − You can write a method or, Class or, interface using generic type once and you can use this code multiple times with various parameters.
Code reuse − You can write a method or, Class or, interface using generic type once and you can use this code multiple times with various parameters.
For certain types, with formal types, you need to cast the object and use. Using generics (in most cases) you can directly pass the object of required type without relying on casting.
For certain types, with formal types, you need to cast the object and use. Using generics (in most cases) you can directly pass the object of required type without relying on casting.
Using generic types you can implement various generic algorithms.
Using generic types you can implement various generic algorithms.