Java Generic Classes
In this page:
Defining a Generic Class
To define a generic class, add angle brackets containing a type parameter, such as <T>, right after your class name. You can then use that parameter to define fields, constructors, and method signatures anywhere inside the class body.
Example: Defining a Generic Class
public class Main {
static class Box<T> {
private T content;
Box(T content) { this.content = content; }
T getContent() { return content; }
}
public static void main(String[] args) {
Box<Integer> intBox = new Box<>(99);
System.out.println(intBox.getContent());
}
}
Login to try C/C++/Java/PHP code in the editor
Multiple Type Parameters
Generic classes can define multiple type parameters when a single placeholder isn't enough, separating them with commas inside the angle brackets, for example <K, V> as used by Map. Each parameter is substituted independently with a concrete type when the class is actually instantiated.
Example: Multiple Type Parameters
public class Main {
static class Pair<K, V> {
K key; V value;
Pair(K key, V value) { this.key = key; this.value = value; }
}
public static void main(String[] args) {
Pair<String, Integer> pair = new Pair<>("Age", 30);
System.out.println(pair.key + " -> " + pair.value);
}
}
Login to try C/C++/Java/PHP code in the editor
Bounded Type Parameters
You can restrict the types allowed into your generic class using bounded type parameters, which is useful when your class needs to call methods that only exist on certain types. The extends keyword restricts the parameter to a class or interface and its subtypes, giving the compiler enough information to allow those method calls.
Example: Bounded Type Parameters
public class Main {
static class NumberBox<T extends Number> {
private T num;
NumberBox(T num) { this.num = num; }
double doubled() { return num.doubleValue() * 2; }
}
public static void main(String[] args) {
NumberBox<Integer> box = new NumberBox<>(10);
System.out.println(box.doubled());
}
}
Login to try C/C++/Java/PHP code in the editor
Generic Interface Implementation
Classes can implement generic interfaces in one of two ways: you can either preserve the generic type parameter in your own class definition and stay generic yourself, or specify a concrete data type at implementation time and lock the interface down to just that type.
Example: Generic Interface Implementation
public class Main {
interface Container<T> {
T get();
}
static class StringContainer implements Container<String> {
public String get() { return "Fixed to String"; }
}
public static void main(String[] args) {
Container<String> c = new StringContainer();
System.out.println(c.get());
}
}
Login to try C/C++/Java/PHP code in the editor
Raw Types and Warnings
Using a generic class without specifying a type parameter creates what's called a 'raw type', a legacy behavior kept around purely for backward compatibility with pre-Generics code. While a raw type still compiles, it triggers compiler warnings and loses all of Generics' type-safety benefits, so it should be avoided in new code.
Example: Raw Types and Warnings
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List rawList = new ArrayList(); // raw type -- compiles but triggers a warning
rawList.add("no type safety");
System.out.println(rawList.get(0));
}
}
Login to try C/C++/Java/PHP code in the editor
Chapter Quiz — Complete all 4 topics to unlock
0/4 topics done
Complete these topics first: