Object-Oriented Programming in Java

Generics


Module VII: Generics. Generics allow you to create classes, methods, and interfaces that operate on data of specific types while ensuring type-safety at compile time. They are widely used in Java Collections, utility classes, and reusable APIs.


Basics of Generics

Generics enable writing type-independent code. Instead of using Object or casting manually, generics ensure compile-time checking.

  • Eliminates unsafe type casting
  • Enables strong type-checking
  • Allows reusable, flexible classes and methods
ArrayList<String> list = new ArrayList<>();
list.add("hello");
// list.add(10);   // compile-time error

Diagram: generic-type-parameter.png


Generic Class

A generic class defines one or more type parameters to be used in the class.

Example: A Simple Generic Box
class Box<T> {
  T value;

  Box(T value) {
    this.value = value;
  }

  T get() { return value; }
}

Box<Integer> b = new Box<>(100);
System.out.println(b.get());
  • T, E, K, V are common type parameter names
  • You can define multiple type parameters, e.g. Box<T, U>

Generic Class with Two Type Parameters

class Pair<K, V> {
  K key;
  V value;

  Pair(K key, V value) {
    this.key = key;
    this.value = value;
  }
}

Pair<String, Integer> p = new Pair<>("age", 20);

Useful in maps, key-value data storage, and utility methods.


Generic Methods

A method can declare its own type parameter independent of the class.

class Utils {
  static <T> void print(T value) {
    System.out.println(value);
  }
}

Utils.print("hello");
Utils.print(123);

Diagram: generic-method-flow.png


Bounded Type Parameters

Bounds restrict the types that can be passed to generics.

class Numbers<T extends Number> {   // only Number subclasses allowed
  T num;
  Numbers(T num) { this.num = num; }
}

Numbers<Integer> n1 = new Numbers<>(10);
Numbers<String> n2 = new Numbers<>("hi"); // error

Bounded generics are widely used in sorting, comparisons, and collections.


Wildcards

Wildcards allow flexibility when working with unknown or partially known types.

  • ? – unknown type
  • ? extends T – upper bounded
  • ? super T – lower bounded
void show(List<?> list) { }           // accepts any type
void showNum(List<? extends Number> l) // only Number or its subclasses

Diagram: wildcards-hierarchy.png


Type Erasure

Java implements generics using type erasure. After compilation, all generic type information is removed and replaced with raw types.

  • Generic type parameters exist only at compile time
  • Ensures backward compatibility with older Java versions
  • Restrictions: no primitive generics, no runtime type-checking of generic types
ArrayList<Integer> a1 = new ArrayList<>();
ArrayList<String> a2 = new ArrayList<>();

// at runtime:
a1.getClass() == a2.getClass();   // true

Summary

Generics help ensure type-safety and reusable code. Understanding generic classes, methods, wildcards, and type erasure prepares you for Java Collections, frameworks, and industry-level application development.

Diagrams to insert: generic-class-diagram.png, wildcard-usage.png