Java Generics – Complete Guide with Examples


Learn Java Generics to create type-safe classes, methods, and collections, understand generic types, wildcards, and how to use them for reusable and robust code.

Generics in Java – Complete Detailed Tutorial

Generics allow classes, interfaces, and methods to operate on types specified as parameters, providing compile-time type safety and reducing runtime errors.

1. What are Generics?

  1. Introduced in Java 5
  2. Parameterizes types (like templates in C++)
  3. Ensures type safety at compile time
  4. Eliminates need for casting objects

Syntax:


class ClassName<T> {
T data; // T is a type parameter

void setData(T data) { this.data = data; }
T getData() { return data; }
}
  1. T is a type parameter
  2. Can also use E (Element), K (Key), V (Value), N (Number)

2. Generic Class Example


class Box<T> {
private T content;

public void setContent(T content) {
this.content = content;
}

public T getContent() {
return content;
}
}

public class Main {
public static void main(String[] args) {
Box<String> stringBox = new Box<>();
stringBox.setContent("Hello Generics");
System.out.println("String Box: " + stringBox.getContent());

Box<Integer> intBox = new Box<>();
intBox.setContent(100);
System.out.println("Integer Box: " + intBox.getContent());
}
}

Output:


String Box: Hello Generics
Integer Box: 100

Key Points:

  1. Type specified at object creation
  2. Provides compile-time type checking

3. Generic Method

  1. Methods can also be generic
  2. Use <T> before return type

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

public class Main {
public static void main(String[] args) {
Integer[] intArray = {1, 2, 3};
String[] strArray = {"A", "B", "C"};

Utils.printArray(intArray);
Utils.printArray(strArray);
}
}

Output:


1 2 3
A B C

4. Bounded Generics

  1. Restrict type parameter to subclass or interface
  2. Syntax: T extends ClassName

class Calculator<T extends Number> {
public double square(T num) {
return num.doubleValue() * num.doubleValue();
}
}

public class Main {
public static void main(String[] args) {
Calculator<Integer> intCalc = new Calculator<>();
System.out.println("Square: " + intCalc.square(5));

Calculator<Double> doubleCalc = new Calculator<>();
System.out.println("Square: " + doubleCalc.square(3.5));
}
}

Output:


Square: 25.0
Square: 12.25

Key Points:

  1. Ensures only Number subclasses used
  2. Avoids type errors at compile time

5. Wildcards in Generics

  1. Unbounded wildcard: <?> – any type
  2. Upper-bounded wildcard: <? extends Class> – subclass of Class
  3. Lower-bounded wildcard: <? super Class> – superclass of Class

import java.util.Arrays;
import java.util.List;

public class Main {
public static void printList(List<?> list) {
for(Object obj : list) {
System.out.print(obj + " ");
}
System.out.println();
}

public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3);
List<String> strings = Arrays.asList("A", "B", "C");

printList(numbers);
printList(strings);
}
}

Output:


1 2 3
A B C

6. Key Points

  1. Generics provide type safety
  2. Reusability: same code works for multiple types
  3. Eliminates casting
  4. Works with classes, interfaces, methods, and collections
  5. Bounded types restrict type parameters
  6. Wildcards allow flexible method arguments

7. Summary

  1. Generics improve code readability, safety, and flexibility
  2. Widely used in Collections Framework
  3. Important for professional Java development