Java · Course navigation

Java generics and bounded types

Write one class and one method that work for many types while the compiler checks them.

On this page
Before you start

Java classes and interfaces.

  • Write one class and one method that work for many types while the compiler checks them.
  • Predict the sample output and explain the state changes.
  • Complete the practice task and check the boundary cases.

The concept

Generics let a class or method have type parameters. Box<T> can hold any one type, but each Box<String> or Box<Integer> is checked by the compiler, so no casts are needed when reading the value. Without generics a container of Object would need casts and could fail at run time.

A bound restricts the type parameter. <T extends Comparable<T>> says that T must be comparable to itself, so the method can call compareTo. Generics are erased at run time, so the JVM sees only the raw type, and primitives cannot be type arguments. Use Integer instead of int.

Code example

Java
import java.util.*;

class Main {
  static class Box<T> {
    private final T value;

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

    T get() {
      return value;
    }
  }

  static <T extends Comparable<T>> T largest(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) {
    Box<String> name = new Box<>("Ada");
    Box<Integer> age = new Box<>(36);
    String upper = name.get().toUpperCase();
    int next = age.get() + 1;
    System.out.println(upper + " " + next);

    System.out.println(largest(Arrays.asList(3, 9, 4)));
    System.out.println(largest(Arrays.asList("pear", "apple", "zebra", "mango")));
  }
}
Output
ADA 37
9
zebra

Follow the code

Open the walkthrough to inspect the example one step at a time.

Show guided walkthrough
Guided walkthroughReady
1import java.util.*;
2
3class Main {
4 static class Box<T> {
5 private final T value;
6
7 Box(T value) {
8 this.value = value;
9 }
10
11 T get() {
12 return value;
13 }
14 }
15
16 static <T extends Comparable<T>> T largest(List<T> items) {
17 T best = items.get(0);
18 for (T item : items) {
19 if (item.compareTo(best) > 0) {
20 best = item;
21 }
22 }
23 return best;
24 }
25
26 public static void main(String[] args) {
27 Box<String> name = new Box<>("Ada");
28 Box<Integer> age = new Box<>(36);
29 String upper = name.get().toUpperCase();
30 int next = age.get() + 1;
31 System.out.println(upper + " " + next);
32
33 System.out.println(largest(Arrays.asList(3, 9, 4)));
34 System.out.println(largest(Arrays.asList("pear", "apple", "zebra", "mango")));
35 }
36}

Follow the example

Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.

View the complete dry-run table
Prepared trace of the published program. Some rows group repeated iterations.
Step / lineWhat happensState after stepOutput so far
T is a type parameter, filled in when a Box is created.—
—
The bound lets the method use compareTo on the items.—
—
get() returns a String, so no cast is needed.upper = "ADA"
—
The Integer is unboxed for the addition.upper = "ADA"
ADA 37
Integers compare numerically.upper = "ADA"
ADA 37
9
Strings compare alphabetically.upper = "ADA"
ADA 37
9
zebra

Behind the scenes

How Java processes this code

The Java compiler produces bytecode. The JVM loads the class and invokes its main method.

Cost and common mistakes

largest is O(n) for n items.

  • You cannot write new T() or List<int>. Type arguments must be reference types.
  • largest fails with an exception on an empty list because items.get(0) is out of range.
  • Generic types are erased at run time, so a List<String> and a List<Integer> have the same class.

Try it yourself

Why not use a List of Object and cast?

Reveal answer and reasoning

Casts can fail at run time with a ClassCastException, while generics let the compiler catch the mistake before the program runs.

Further reading