Generics and Templates

Lesson 0017 — 45 min read

Generics (Java / Python) and Templates (C++) allow developers to write reusable, type-safe classes, interfaces, and methods that operate across multiple data types without code duplication or manual type casting.

Why Generics and Templates?

1. Generic / Template Classes

A generic class uses a type parameter placeholder (e.g., T) that is replaced with a concrete type upon instantiation.

class Box<T> {
    private T value;

    public void set(T value) { this.value = value; }
    public T get() { return value; }
}

public class Main {
    public static void main(String[] args) {
        Box<Integer> intBox = new Box<>();
        intBox.set(100);
        System.out.println(intBox.get()); // 100

        Box<String> strBox = new Box<>();
        strBox.set("Hello Generics");
        System.out.println(strBox.get()); // Hello Generics
    }
}
#include <iostream>
#include <string>
using namespace std;

template <typename T>
class Box {
private:
    T value;
public:
    void set(T value) { this->value = value; }
    T get() { return value; }
};

int main() {
    Box<int> intBox;
    intBox.set(100);
    cout << intBox.get() << "\n"; // 100

    Box<string> strBox;
    strBox.set("Hello Templates");
    cout << strBox.get() << "\n"; // Hello Templates
    return 0;
}
from typing import TypeVar, Generic

T = TypeVar("T")

class Box(Generic[T]):
    def __init__(self) -> None:
        self.value: T

    def set(self, value: T) -> None:
        self.value = value

    def get(self) -> T:
        return self.value

def main():
    int_box = Box[int]()
    int_box.set(100)
    print(int_box.get()) # 100

    str_box = Box[str]()
    str_box.set("Hello Generics")
    print(str_box.get()) # Hello Generics

if __name__ == "__main__":
    main()

2. Generic / Template Methods

You can declare generic methods within non-generic or generic classes. The type parameter is specified before the method return type.

class Printer {
    public <T> void printData(T data) {
        System.out.println("Data: " + data);
    }
}

public class Main {
    public static void main(String[] args) {
        Printer p = new Printer();
        p.printData(100);        // Data: 100
        p.printData("Generics"); // Data: Generics
        p.printData(3.14);       // Data: 3.14
    }
}
#include <iostream>
#include <string>
using namespace std;

template <typename T>
void printData(T data) {
    cout << "Data: " << data << "\n";
}

int main() {
    printData(100);
    printData(string("Templates"));
    printData(3.14);
    return 0;
}
from typing import TypeVar

T = TypeVar("T")

def print_data(data: T) -> None:
    print("Data:", data)

def main():
    print_data(100)
    print_data("Generics")
    print_data(3.14)

if __name__ == "__main__":
    main()

3. Bounded Type Parameters (Constraints)

Bounded type parameters restrict acceptable types for generic arguments to specific class hierarchies or interfaces.

class NumericBox<T extends Number> {
    private T num;
    public NumericBox(T num) { this.num = num; }

    public double square() {
        return num.doubleValue() * num.doubleValue();
    }
}

public class Main {
    public static void main(String[] args) {
        NumericBox<Integer> intBox = new NumericBox<>(10);
        System.out.println(intBox.square()); // 100.0

        // Compile-time error!
        // NumericBox<String> strBox = new NumericBox<>("Hello");
    }
}
#include <iostream>
#include <type_traits>
using namespace std;

// C++20 Concept
template <typename T>
concept Numeric = is_arithmetic_v<T>;

template <Numeric T>
class NumericBox {
private:
    T num;
public:
    NumericBox(T num) : num(num) {}
    double square() { return (double)num * (double)num; }
};

int main() {
    NumericBox<int> intBox(10);
    cout << intBox.square() << "\n"; // 100.0

    // Compile-time error!
    // NumericBox<string> strBox("Hello");
    return 0;
}
from typing import TypeVar
from numbers import Number

T = TypeVar("T", bound=Number)

def square(num: T) -> float:
    return float(num) * float(num)

def main():
    print(square(10))   # 100.0
    print(square(5.5))  # 30.25
    # static type checker flags: square("Hello")

if __name__ == "__main__":
    main()

4. Wildcard Types (Java) & Python Helpers

In Java, wildcards (?) handle unknown or variable generic arguments:

In Python, typing helpers like Any, Union, and variance annotations provide similar static checking flexibility.

5. Under the Hood: Type Erasure vs Template Instantiation

Languages handle generic type implementation differently at compile time and runtime:

Comparison Summary

Aspect Java C++ Python
Implementation Generics (<T>) Templates (template <typename T>) Type Hints (TypeVar / Generic[T])
Under the Hood Type Erasure (replaced with Object at compile-time) Template Instantiation (generates machine code per type) Ignored at runtime (used by static type checkers like mypy)
Type Safety Enforced at compile-time Enforced at compile-time Static type checking only (not runtime enforced)
Bounded Constraints <T extends Class> / Wildcards (? extends, ? super) C++20 Concepts (requires / concept) TypeVar("T", bound=Class)
Raw Types Supported (legacy raw List without <T>) Not allowed (requires concrete type parameters) Omitting type hints defaults to dynamic typing

What is Java Type Erasure?

How do C++ Templates differ from Java Generics at compiled runtime?

Notes

Generics and Templates :-

Purpose ⇒ Type-safe, reusable classes & methods without code duplication

Syntax ⇒ Java <T> ; C++ template <typename T> ; Python TypeVar("T")

Bounded Constraints :-

Java ⇒ <T extends Number> ; Wildcards (? extends T read-only, ? super T write-only)

C++ ⇒ C++20 Concepts (template <Numeric T> ; concept Numeric = is_arithmetic_v<T>)

Python ⇒ TypeVar("T", bound=Number) for static type checkers

Under the Hood Behavior :-

Java Type Erasure ⇒ Strips <T> at compile-time ; replaces with Object for JVM backward compatibility

C++ Template Instantiation ⇒ Compiler generates dedicated binary code per type ; maximum performance

Python Static Typing ⇒ Type hints used by mypy/IDEs ; ignored by Python runtime

Primary source: Oracle Java Tutorials — Generics, cppreference — Templates & Python Docs — typing module. Ask me anything that's unclear.

← Prev: Exception Handling Next: File Handling →

Questions? Ask your agent — you can follow up on any concept, quiz answer, or how this applies to a specific coding problem. Review the Java glossary or syntax quick reference for a compressed overview.