English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Java Basic Tutorial

Java Flow Control

Java Array

Java Object-Oriented (I)

Java Object-Oriented (II)

Java Object-Oriented (III)

Java Exception Handling

Java List (List)

Java Queue (Queue)

Java Map Collection

Java Set Collection

Java Input Output (I/O)

Java Reader/Writer

Java Other Topics

Java Generics

In this tutorial, we will learn about Java generics through examples, how to create generic classes and methods, and their advantages.

In Java,GenericIt helps to create classes, interfaces, and methods that can be used with different types of objects (data). Therefore, it allows us to reuse our code.

Note:Note:GenericGenerics are not applicable to primitive types (int, float, char, etc.).

How to use Java generics

To understand how to useGenericwe can use classes from the Java collection framework.

The ArrayList class is an example of a generic class. We can use ArrayList to store any type of data. For example

import java.util.ArrayList;
class Main {
   public static void main(String[] args) {
      //Create an array list to store Integer data
      ArrayList<Integer> list1 = new ArrayList<>();
      list1.add(4);
      list1.add(5);
      System.out.println("ArrayList of Integer: ") + list1);
      //Create an array list to store String data
      ArrayList<String> list2 = new ArrayList<>();
      list2.add("Four");
      list2.add("Five");
      System.out.println("ArrayList of String: ") + list2);
      //Create an array list to store Double data
      ArrayList<Double> list3 = new ArrayList<>();
      list3.add(4.5);
      list3.add(6.5);
      System.out.println("ArrayList of Double: ", + list3);
   }
}

Output result

ArrayList of Integer: [4, 5]
ArrayList of String: [Four, Five]
ArrayList of Double: [4.5, 6.5]

In the above example, we used the same ArrayList class to store elements of types Integer, String, and Double. SinceJava generics, which is possible.

Please note this line here,

ArrayList<Integer> list1 = new ArrayList<>();

We used Integer inside the angle brackets <> in generics. Angle brackets <> are calledType parameters.

The parameter type is used to specify the type of object (data) that the generic class or method is applicable to.

Creating a generic class

Now that we know how generics work in Java, let's see how to create our own generic class.

Example: Creating a generic class

class Main {
  public static void main(String[] args) {
    //Initialize the generic class with integer data
    GenericsClass<Integer> intObj = new GenericsClass<>(5);
    System.out.println("The generic class returns:", + intObj.getData());
    //Initialize the generic class with string data
    GenericsClass<String> stringObj = new GenericsClass<>("Java Programming");
    System.out.println("The generic class returns:", + stringObj.getData());
  }
}
class GenericsClass<T> {
  //Type variable T
  private T data;
  public GenericsClass(T data) {
    this.data = data;
  }
  //Method to return a variable of type T
  public T getData() {
    return this.data;
  }
}

Output result

The generic class returns: 5
The generic class returns: Java Programming

In the above example, we created a generic class named GenericsClass. This class can be used to handle any type of data.

class GenericsClass<T> {...}

Here, T representsType parametersInside the Main class, we created GenericsClass objects named intObj and stringObj.

  • When creating intObj, the type parameter T is replaced with Integer. This means that intObj uses GenericsClass to handle integer data.

  • When creating stringObj, the type parameter T is replaced with String. This means that stringObj uses GenericsClass to handle string data.

Creating generic methods

Similar to generic classes, we can also create our own generic methods in Java.

Example: Creating a generic method

class Main {
  public static void main(String[] args) {
    //Using Integer data to initialize the class
    DemoClass demo = new DemoClass();
    demo.<String>genericMethod("Java Programming");
  }
}
class DemoClass {
  //Generic methods
  public <T> void genericsMethod(T data) {
    System.out.println("This is a generic method.");
    System.out.println("The data passed to the method is "); + data);
  }
}

Output result

This is a generic method.
The data passed to the method is: Java Programming

In the above example, we created a generic method named genericsMethod within a regular class (DemoClass).

public <T> void genericMethod(T data) {...}

Here, the type parameter <T> is inserted after the modifier (public) and before the return type (void).

We can call a generic method by placing the actual type <String> in front of the method name in the parentheses.

demo.<String>genericMethod("Java Programming");

Note: In most cases, we can omit the type parameter when calling a generic method. This is because the compiler can use the value passed to the method to match the type parameter. For example,

demo.genericsMethod("Java Programming");

bounded type

Generally speaking,Type parameterIt can accept any data type (except primitive types). However, if we want to use generics only for certain specific types (such as accepting numeric data types), we can use bounded types.

We use the extends keyword. For example,

<T extends A>

This means that T can only accept data types that are subclasses of A.

Example: Bounded types

class GenericsClass<T extends Number> {
  public void display() {}}
    System.out.println("This is a bounded type generics class.");
  }
}
class Main {
  public static void main(String[] args) {
    //Create a GenericsClass object
    GenericsClass<String> obj = new GenericsClass<>();
  }
}

In the above example, we created abounded typeof the generic class. Here, note the expression

<T extends Number>

This means that T can only use subtypes of Number data types (Integer, Double, etc.).

However, we have already created an object of the generic class using String. This is why when we run the program, we get the following error.

GenericsClass<String> obj = new GenericsClass<>();
                                                 ^
    reason: inference variable T has incompatible bounds
      equality constraints: String
      lower bounds: Number
  where T is a type-variable:
    T extends Number declared in class GenericsClass

Advantages of Java generics

1. Code reusability

GenericThis allows us to write code that is applicable to different types of data. For example,

public <T> void genericsMethod(T data) {...}

Here, we create a generic method. This method can be used to perform operations on integer data, string data, and so on.

2. Compile-time type checking

GenericType parameterProvide information about the data type used in generic code.

Therefore, any errors can be identified at compile time, which is easier to fix than runtime errors. For example,

//Without using generics
NormalClass list = new NormalClass();
//Calling the method of NormalClass
list.display("String");

In the above code, we have a regular class. We call the method named display() of this class by passing string data.

Here, the compiler does not know if the value passed in the parameter is correct. But let's see what happens if we use a generic class instead.

//Use generics
GenericsClass<Integer> list = new GenericsClass<>();
//Call the method of GenericsClass
list2.display("String");
In the above code, we have a generic class. Here, the type parameter indicates that this class is processing Integer data.
Therefore, when string data is passed as a parameter, the compiler will generate an error.

3. Generics used with collections

The collection framework uses the generic concept in Java. For example,

// Create a string type ArrayList
ArrayList<String> list1 = new ArrayList<>();
// Create an integer type ArrayList
ArrayList<Integer> list2 = new ArrayList<>();

In the above example, we used the same ArrayList class to handle different types of data.

Like ArrayList, other collections (LinkedList, Queue, Maps, etc.) are also Java generics.