Tutorials Logic, IN info@tutorialslogic.com

Generics in Java Generic Classes Methods

Why Generics Matter

Java generics move many type errors to compilation. Bounds and wildcards describe which producers and consumers are accepted without falling back to unsafe raw types.

Express Java type relationships with parameters, bounds, and wildcards so reusable APIs remain checked without raw types or unsafe casts.

Before generics, code often stored Object and required manual casts. Generics make the expected type part of the declaration.

Generic List

Generic List
import java.util.ArrayList;
import java.util.List;

public class GenericListDemo {
    public static void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("Asha");

        String first = names.get(0); // no cast needed
        System.out.println(first.toUpperCase());
    }
}

Generic Classes and Methods

Create a generic class when the same logic should work with different types. Create a generic method when only one method needs type flexibility.

Generic Box

Generic Box
class Box<T> {
    private T value;

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

    T get() {
        return value;
    }
}

Generic Method

Generic Method
public class GenericMethodDemo {
    static <T> void printArray(T[] values) {
        for (T value : values) {
            System.out.println(value);
        }
    }
}

Bounds and Wildcards

Bounds restrict the type parameter. Wildcards allow flexible method parameters when exact generic types differ.

Bounded Type Parameter

Bounded Type Parameter
public class BoundedGenericDemo {
    static <T extends Number> double sum(T a, T b) {
        return a.doubleValue() + b.doubleValue();
    }
}

Type Erasure

Java implements generics using type erasure. Generic type information is checked at compile time but mostly removed at runtime.

  • You cannot create new T[] directly.
  • You cannot use instanceof List<String>.
  • Generic overloads that erase to the same signature are not allowed.

Type Safety with Generics

Generics let the compiler check element types before runtime. A List<String> communicates intent and prevents accidental insertion of Integer, Student, or other unrelated values.

  • Avoid raw List and Map types.
  • Use bounded generics when a type must extend a base type.
  • Use ? extends for reading producer values.
  • Use ? super for writing consumer values.

How generics protect Java code from wrong types

Generics let a class, interface, or method work with a type chosen by the caller while still keeping compile-time type safety. Without generics, collections can accept Object values and mistakes may appear later as ClassCastException. With generics, Java checks the expected type before the program runs.

The most important idea is that T, E, K, and V are placeholders, not special data types. They are replaced by real types such as String, Integer, Student, or Product when the generic code is used. Bounded generics add one more rule: they allow only types that extend a certain class or implement a certain interface.

  • Use List<String> when every item should be text.
  • Use a generic class when the same storage logic should work for different value types.
  • Use bounded generics when the method needs behavior from a parent type.
  • Avoid raw types because they remove the safety generics provide.

Generic method that prints any typed list

Generic method that prints any typed list
static <T> void printItems(List<T> items) {
    for (T item : items) {
        System.out.println(item);
    }
}

printItems(List.of("Java", "Spring"));
Before you move on

Generics in Java Generic Classes Methods Mastery Check

5 checks
  • Before generics, code often stored Object and required manual casts.
  • Generics make the expected type part of the declaration.
  • Create a generic class when the same logic should work with different types.
  • Create a generic method when only one method needs type flexibility.
  • Wildcards allow flexible method parameters when exact generic types differ.

Core Java Questions Learners Ask

They discard compile-time type checks and can move failures to runtime casts.

It accepts a producer of Number subtypes, but adding values is restricted.

It accepts Integer values into a consumer whose element type is Integer or a superclass.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.