Java Programs›OOP›Create a Generic Stack Class

Create a Generic Stack Class in Java

intermediate·  OOP  ·  Generics

Problem

A generic class declares a type parameter such as T, which callers fill in with a real type; the compiler then checks every use, so the wrong type can't be added and no casts are needed.

Implement a stack that works for any element type, and use it for both browser pages (strings) and numbers.

Input
push home, products, cart → pop
Output
pops cart, top becomes products

Java Program

Java
import java.util.ArrayList; import java.util.EmptyStackException; import java.util.List; public class GenericStack { static class Stack<T> { // T is filled in by the caller: Stack<String>, Stack<Integer>, ... private final List<T> items = new ArrayList<>(); void push(T item) { items.add(item); } T pop() { if (items.isEmpty()) throw new EmptyStackException(); return items.remove(items.size() - 1); } T peek() { if (items.isEmpty()) throw new EmptyStackException(); return items.get(items.size() - 1); } boolean isEmpty() { return items.isEmpty(); } } public static void main(String[] args) { Stack<String> pages = new Stack<>(); pages.push("home"); pages.push("products"); pages.push("cart"); System.out.println("Top: " + pages.peek()); System.out.println("Back from: " + pages.pop()); System.out.println("Now on: " + pages.peek()); Stack<Integer> numbers = new Stack<>(); // same class, different type, no casts needed numbers.push(42); int value = numbers.pop(); System.out.println("Popped number: " + value + ", empty: " + numbers.isEmpty()); } }

Output

Top: cart Back from: cart Now on: products Popped number: 42, empty: true

Core Logic

Declaring the class as Stack&lt;T&gt; lets one implementation serve every element type while the compiler enforces the type chosen at each use.

How It Works
  1. 1T appears in the field List&lt;T&gt; and in the method signatures push(T), pop() and peek().
  2. 2Stack&lt;String&gt; accepts only strings, so pushing a number there is a compile-time error.
  3. 3pop and peek throw EmptyStackException instead of failing with an index error.
  4. 4Stack&lt;Integer&gt; reuses the same class; int value = numbers.pop() unboxes without a cast.
After pushing three pages, pop() returns cart and peek() then shows products.
💡

Key Point: Generics are checked at compile time and erased at run time — inside the class, new T() or new T[10] isn't allowed, because the JVM doesn't know what T is.

Key Concepts

type parameter <T>generic classEmptyStackExceptionautoboxing

Approach 2: Generic Method with a Bounded Type

Java
import java.util.Arrays; import java.util.List; public class GenericBoundedMethod { // <T extends Comparable<T>>: T can be any type whose values can be compared with each other static <T extends Comparable<T>> T max(List<T> items) { T best = items.get(0); for (T item : items) { if (item.compareTo(best) > 0) best = item; } return best; } public static void main(String[] args) { System.out.println(max(Arrays.asList(4, 19, 7, 11))); System.out.println(max(Arrays.asList("pear", "apple", "plum"))); System.out.println(max(Arrays.asList(2.5, 0.75, 1.25))); } }

Output

19 plum 2.5

Core Logic

A generic method declares its own type parameter, and a bound such as T extends Comparable&lt;T&gt; lets it call compareTo on any type that supports it.

How It Works
  1. 1&lt;T extends Comparable&lt;T&gt;&gt; before the return type declares the method's type parameter and its bound.
  2. 2Because every T is Comparable, item.compareTo(best) compiles.
  3. 3The same method finds the maximum of integers, strings and doubles.
For the strings, plum is the maximum because it comes last alphabetically.
💡

Key Point: Without the bound, the compiler would only know T is an Object, and compareTo wouldn't compile.

Key Concepts

generic methodbounded type parameterComparable

Interview Questions

What is type erasure?

The compiler checks generic types and then removes them, so at run time a Stack<String> and a Stack<Integer> are the same class. That's why you can't write new T() or check obj instanceof Stack<String>.

Why can't a generic class use a primitive type like Stack<int>?

Type parameters must be reference types. Use the wrapper class, Stack<Integer>, and autoboxing converts between int and Integer automatically.

Learn the Concept

Related Programs