Generic Class in Java | Generic Method, Example

A class that is declared generic type is called generic class in java. It is type-safe and can act upon any data type.

A generic class is also called “parameterized types” because it uses a parameter that determines which data type it should work upon.

The main advantage of creating a generic class is when a generic class is created, we do not need to create the same class again whenever we want to use that class for a new data type. The same generic class can work with all different types of data.

Java Generic class is designed to work upon objects. Hence, it cannot work with primitive data types.

Since a generic class works on any kind of data type, we cannot specify a specific data type such as Integer, String, etc when creating the generic class.

The general syntax to declare a generic class in java using a generic parameter (type parameter) <T> is as follows:

class class-name<T>
{
     // class code.
}
Or, class class-name<type-parameter-list> {
    // class code
}
For example:
class Myclass<T>
{
    // class code
}

Here, the type parameter is determined at the time of compilation, which data type actually we want to use with this class.

The value of type parameter can be a class, interface, or any other type except primitive data type such as int, float, double, etc.

By creating a generic class in java, we can store different types of objects.

Moreover, a generic class can have more than one type parameter separated by a comma, and hence, it can also be termed as a parameterized class.

The general syntax for the declaration of a simple generic class having two parameters T and V is as follows:

class Myclass<T, V>
{
// class code.
}

How to create an object of Generic Class in Java?


The general syntax to create an object of generic class in java is as follows:

class-name<type-arg-list> var-name = new class-name<type-arg-list>(cons-arg-list);
For example:
Myclass<Integer> obj = new Myclass<Integer>(); // creating a generic type object of Integer type.

Here, we have specified <Integer> data type after Myclass name. This means that the type parameter T assumes Integer data type and Java compiler creates the following class internally.

// A non-generic version of Myclass.
    class Myclass  {
        Integer obj;
   }

The preceding code is compiled by the compiler and is executed by JVM. Here, the main point is to be noted that whenever a generic class or interface is created, Java compiler internally constructs a non-generic version of the class or interface by substituting the specified data type in the place of type parameter T. This is called erasure in java.

Thus, we can define erasure as “creating a non-generic version of a generic type by java compiler is termed as erasure”.

Java Diamond Syntax


In the previous section, we discussed how to create a generic type object. To simplify our life, Java SE 7 added the diamond syntax, in which the type parameters may be omitted for invoking the constructor.

We can just leave it to the Java compiler to understand the types from the type declaration. For example, the diamond syntax to create a generic class instance in java is as follows:

Myclass<String> obj = new Myclass<>();

Example Program based on Generic Class


1. Let’s create a simple program where we will create a generic class Myclass in which we will store an object of any data type.

Program source code 1:

// A generic class to store any type of object.
// Here, T is generic type parameter which determines type of data.
public class Myclass<T>
{
// Declare a variable obj of type T.
     T obj;
// Declare a constructor to initialize obj of type T.
     Myclass(T obj) {
        this.obj = obj;
      }
// Declare an instance method that will return T type object.
     T getObj()
     {
        return obj; 
      }
  }
public class GenericClassTest {
public static void main(String[] args) 
{
// Create an instance of Myclass class to store Integer type object. 
     Myclass<Integer> obj1 = new Myclass<Integer>(50);
// Call getObj() to retrieve Integer object.
     System.out.println("Value stored: " +obj1.getObj());
   
// Similarly, use Myclass to store float object and retrieve it.
     Myclass<Float> obj2 = new Myclass<Float>(50.20f);
     System.out.println("Value stored: " +obj2.getObj());
   
// Use Myclass to store String type object and retrieve it.
     Myclass<String> obj3 = new Myclass<>("Ivaan Sagar"); // Diamond syntax.
     System.out.println("Value stored: " +obj3.getObj());
  }
}
Output:
         Value stored: 50
         Value stored: 50.2
         Value stored: Ivaan Sagar

In this program, we have created three times objects of Myclass and stored three different objects: Integer object, Float object, and String object into it.

In the program, we have used diamond syntax to create an object of Myclass to store String type object. Since Myclass is a generic type, don’t forget to use the diamond operator < > in the initialization expression, otherwise, the compiler will treat it as a raw type.


2. Let’s consider another example program. In this program, we will create a generic class that can hold objects of two different types T1 and T2.

Program source code 2:

// A generic class to store objects of two different types.
// Here, T1 and T2 are two generic type parameters which determine type of data.
public class Myclass<T1, T2>
{
// Declare two variables obj1 and obj2 of type T1 and T2.
     T1 obj1;
     T2 obj2;
// Declare a constructor having two parameters one and two of type T1 and T2.
   Myclass(T1 one, T2 two)
   {
	 obj1 = one;
	 obj2 = two;
   }
   T1 getObject1()
   {
	 return obj1;  
   }
   T2 getObject2()
   {
	 return obj2;  
   }
}
public class GenericClassTest {
public static void main(String[] args) 
{
 Myclass<String, Integer> obj = new Myclass<String, Integer>("Herry", 20);
 System.out.println(obj.getObject1()+ " " +obj.getObject2());
  }
}
Output:
          Herry 20

When using the Myclass class, we must specify which specific data types we are going to use in place of T1 and T2.

For example, in this program, we have used String and Integer for Myclass, as in Myclass<String, Integer> in the main() method.

Now, we will understand how generic actually works. Concentrate on the below source code.

// How Myclass<String, Integer> can be treated internally.
class Myclass 
{
   String obj1;
   Integer obj2;
Myclass(String one, Integer two) 
{
   obj1 = one;
   obj2 = two;
}
public String getObject1() 
{
   return obj1;
}
public Integer getObject2() 
{
    return obj2;
  }
}

As you can understand from the above lines of code how generics actually work. With this, we can understand how the getObject1() and getObject2() methods return String and Integer values in the main() method.

Note that the types must match exactly. Otherwise, you will get a compile-time error. For example:

Myclass<String, Integer> obj = new Myclass<String, String>("Herry", 20); // Compile time error.

Generic Method in Java


Similar to generic classes, we can also create generic methods. A method that takes generic type parameters is called generic method in java.

A generic type can be applied for the static method. We can define a generic method by putting generic type parameter <T> before the method return type and immediately after the keyword static.

The general syntax to declare a generic method in java is as follows:

public static <T> void display(T[ ] list)
{
// method code;
}

In the above syntax, the method is called a generic method that can work on all different types of data. To represent data type, we have specified T in the angle brackets <>.

How to call Generic Method in Java?


To call a generic method in java, prefix the method name with the actual type in angle brackets. The general syntax to call a generic method is as follows:

class-name.<T>method-name(argument-list);
For example:
Myclass.<Integer>display(arr); // Here, arr is the array reference.

or simply invoke it as follows:

display(arr);
display(strings);

In the latter case, the actual type is not explicitly specified. So, Java compiler automatically determines the actual type.

Use of Generic Method in Java


Generic methods are useful for writing methods that are applicable to any data type while the functionality remains the same. For example, there are various generic methods available in the java.util.Collections class.

Example Program based on Generic Method


1. Let’s create a program where we will define a generic method that will accept an array and display elements of the array. The elements of an array may be of any data type.

Program source code 1:

// A generic method used to read and display any type of array elements.
public class Myclass 
{
// This generic method receives the T type array.
  public static <T> void display(T[] array)
  {
  // Now, we will use for each loop and reads elements of array.
	 for(T t : array) {
	  System.out.print(t+ " ");	 
	 }
   System.out.println();	 
  }
}
public class GenericMethodTest {
public static void main(String[] args)
{
// Read elements of array of Integer type using generic display() method.
     Integer[ ] arr1 = {20, 30, 40, 50, 60, 70};	
     System.out.println("Reading Integer objects: ");
     Myclass.display(arr1);
   
// Read elements of array of Double type using generic display method. 
     Double[ ] arr2 = {20.20, 30.30, 40.40, 50.50, 60.60};
     System.out.println("Reading Double objects: ");
     Myclass.display(arr2);
   
// Read elements of array of String type using generic display method.
     String[ ] arr3 = {"Dhanbad", "New York", "Sydney", "Paris", "London"};
     System.out.println("Reading String objects: ");
     Myclass.display(arr3);
  }
}
Output:
        Reading Integer objects: 
        20 30 40 50 60 70 
        Reading Double objects: 
        20.2 30.3 40.4 50.5 60.6 
        Reading String objects: 
        Dhanbad New York Sydney Paris London 

2. Let’s create another simple program based on the utilities of the generic method.

Program source code 2:

import java.util.List;
public class Utilities 
{
  public static <T>  void m1(List<T> list, T val) 
{
  for(int i = 0; i < list.size(); i++)
  {
	list.set(i, val); 
   }
 }
}
import java.util.ArrayList;
import java.util.List;
public class UtilitiesMethodTest {
public static void main(String[] args) 
{
 List<Integer> list = new ArrayList<Integer>();
  list.add(10);
  list.add(20);

 System.out.println("Original list: " + list);
 Utilities.<Integer>m1(list, 50);
 System.out.println("List after calling Utilities.m1() method: " + list);
 }
}
Output:
         Original list: [10, 20, 30]
         List after calling Utilities.m1() method: [50, 50, 50]

As you can observe that the set() method used in generic method takes the index position as the first argument and the actual value to be set as the second argument.


Key Points:

After discussing generic class and generic method in java, we can conclude the following key points:

1. A generic class represents that is type-safe.

2. A generic class and a generic method can handle any type of data.

3. Generics can work only with objects of any class. They cannot work on primitive data types.

4. A generic class and a generic method eliminate the need of re-writing code every time there is a change in a data type.

5. Java compiler constructs a non-generic version of the class by putting the specified data type in a generic class. This is called erasure.

6. By using generic types, we can easily eliminate type casting in many cases.

7. All the classes of java.util package has been revised using generics.

8. We cannot create an object of generic type parameter. For example,

class Myclass<T> // Here, T is generic parameter.
T obj = new T(); // Invalid.

Hope that this tutorial has elaborated enough points related to generic class and generic method in java with several example programs. I hope that you will have understood the basic concepts of generic class and generic method.
Thanks for reading!!!