Curriculum
Course: Learn Java Programming
Login

Curriculum

Learn Java Programming

Text lesson

Overview of Generics in Java

In this lesson, you will learn.

  • What are Generics
  • Advantages of Generics
  • What is the Need for Generics
  • Using Generics: Examples
  • Generic Class With Two Parameter Types
  • Examples

 

1. What are Generics?

  1. Generics in Java enable the creation of classes, interfaces, and methods that can operate with various data types while maintaining type safety.

  2. Generics refer to parameterized types, which enable the specification of types during code usage rather than when it is defined.

  3. Generics help in catching type errors at compile time, eliminating the need for casting, and enabling the implementation of generic algorithms.

 

Generics were introduced to Java in JDK 5.0 in 2004.

 

2. Advantages of Generics

A principal advantage of generic code is that it will automatically work with the type of data passed to its type parameter.

Many algorithms are logically the same, no matter what type of data they are applied to. For example, a Quicksort is the same whether it is sorting items of type Integer, String, Object, or Thread. With generics, you can define an algorithm once, independently of any specific type of data, and then apply that algorithm to a wide variety of data types without any additional effort.

The following are the advantages of generics.

  • Code Reusability — The common Java code can be used with multiple object types.
  • Compile-Time Safety — Java checks the generics code at compile time against errors instead of at runtime.
  • Type Safety — We can restrict adding unnecessary data.
  • Usage in Collections — Collections need object types to deal with data.

 

Generics enable stronger type checks at compile time and can be used to develop robust and reusable code components.

 

3. What is the Need for Generics

Let’s illustrate this with a Printer class designed to display text and numbers using different approaches – first without generics and then with generics.

Using a traditional approach, you have to create 2 classes since we have 2 different types of data, i.e., Number(Integer) and Text(String).

 

Create a class NumberPrinter for Printing Numbers

public class NumberPrinter {
    private final Integer value;

    public NumberPrinter(Integer value) {
        this.value = value;
    }

    public void printData() {
        System.out.println("Printing: " + value);
    }
}

 

Create a class TextPrinter for Printing Text Data

public class TextPrinter {
    private final String value;

    public TextPrinter(String value) {
        this.value = value;
    }

    public void printData() {
        System.out.println("Printing: " + value);
    }
}

 

Creating a Driver Class, i.e., Printer

public class Printer {
    public static void main(String[] args) {
        NumberPrinter numberObj = new NumberPrinter(10);
        numberObj.printData(); // output = print: 10
        TextPrinter textObj = new TextPrinter("Learning Generics");
        textObj.printData();   // output = print: Learning Generics
    }
}

 

Here, you can see, there is a code duplication due to only a change in the data types(Integer and String). So, here the data type is only the difference!

So, let’s understand the concept of Generics to avoid code duplication.

 

4. Printing Data Using Generics

Let’s implement the above example using a Generic Printer class.

public class Printer<T> {
    private final T value;

    public Printer(T value) {
        this.value = value;
    }

    public void printData() {
        System.out.println("Printing: " + value);
    }
}

 

To use this Printer class for different types, you simply instantiate it with the desired data type.

Printer<Integer> integerPrinter = new Printer<>(15);
integerPrinter.printData();   // output = print: 15

Printer<String> stringPrinter = new Printer<>("Learning Generics");
stringPrinter.printData();   // output = print: Learning Generics

 

Explanation

Here, only one class (Printer) is required to print different data types.

Printer<T>: Here, T is the name of a type parameter contained within the angle bracket (< >) that can be used to declare a type as a common standard.

This name is used as a placeholder for the actual type that will be passed to the Printer when an object is created.

We can create the Printer objects for other data types, also like Double/Long. So, the Code reusability is achieved in style.

Printer(T value): This will accept a value of type T (any type). Whatever type is specified for an instance of Printer.

 

Example 1: Creating a Generic Box Class

package genericclass;

public class Box<T> {
    private T t; // T stands for "Type"

    public void set(T t) {
        this.t = t;
    }

    public T get() {
        return t;
    }

    public static void main(String[] args) {
        Box<Integer> integerBox = new Box<>();
        integerBox.set(10);
        System.out.println("Box contains: " + integerBox.get());

        Box<String> stringBox = new Box<>();
        stringBox.set("Hello World");
        System.out.println("Box contains: " + stringBox.get());
    }
}

Output

Box contains: 10
Box contains: Hello World

 

Explanation: The Box class is a generic container for different types of objects. By specifying the type parameter <T>, It can safely hold any type, ensuring type safety and reducing the need for casts.

 

Example 2: Display Array Elements

package genericclass;

public class ArrayPrinter<T> {
	
    public void printArray(T[] array) {
        for (T element : array) {
            System.out.print(element + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        ArrayPrinter<String> stringPrinter = new ArrayPrinter<>();
        stringPrinter.printArray(new String[]{"Hello", "World"});

        ArrayPrinter<Integer> integerPrinter = new ArrayPrinter<>();
        integerPrinter.printArray(new Integer[]{1, 2, 3, 4});
    }
}

Output

Hello World 
1 2 3 4 

5. A Generic Class With Two Type Parameters

Generic classes can also accept multiple types, as demonstrated in the example where they can accept both Integer and String.

 

Example: A Generic Class With Two Type Parameters

The following example accepts both Integer and String.

public class MultiPrinter<T, V> {
    private final T value1;
    private final V value2;

    public MultiPrinter(T value1, V value2) {
        this.value1 = value1;
        this.value2 = value2;
    }

    public void printValue() {
        System.out.println("print: " +value1 + " : " + value2);
    }
}

//Using this class
MultiPrinter<Integer, String> multiPrinter = new MultiPrinter<>(15, "Hi");
multiPrinter.printValue(); // output = print: 15 : Hi

 

Important Point!

Generics Work Only with Reference Types

When declaring an instance of a generic type, the type argument passed to the type parameter must be a reference type.

You cannot use a primitive type, such as int or char.

Printer<int> intOb = new Printer<int>(53); 
// Error, can't use primitive type

 

Java Type Naming Conventions

  • E — Element (used in Collections)
  • K — Key (Used in Map)
  • N — Number
  • T — Type
  • V — Value (Used in Map)
  • S, U, V, etc. — 2nd, 3rd, 4th types

 

 

 

 


End of the lesson….enjoy learning

 

 

Student Ratings and Reviews

 

 

 

There are no reviews yet. Be the first one to write one.

 

 

Submit a Review

 

 

Layer 1
Login Categories