What is a generic class in Java, and how do you declare one with a type parameter?
answer
- Type parameter in <> after the class name: class Box<T>
- T usable in fields, params, return types
- Type argument supplied at use: Box<String> (parameterized type)
- Diamond <> infers the argument
- Erasure: one class at runtime, T becomes its bound
basics
~20 sA generic class is a class that takes a type as a parameter, written in angle brackets after the class name, like class Box<T>. You then use T as a placeholder type inside the class for fields and methods. When you create an object you supply a real type, e.g. Box<String>.
solid answer
~40 sA generic class is a class parameterized over one or more types. You declare it by adding a type-parameter section in angle brackets right after the class name: class Box<T>. Inside the class, T behaves like a real type you can use for fields (private T value), method parameters (void set(T v)), and return types (T get()). The single uppercase letter is just a conventional name. When you use the class you create a parameterized type by supplying a concrete type argument, Box<String>, which makes the compiler treat every T as String for that instance, giving you compile-time type safety and removing casts. The same idea applies to interfaces: interface Container<T> { T get(); }. Generics replaced the old approach of using Object plus manual casts.
go deeper
Can declare class Box<T>, use T for a field and a get/set method, and instantiate Box<String> with the diamond operator.
Explains the type parameter vs type argument distinction, multiple parameters (Pair<K,V>), generic interfaces, and that raw types lose safety.
Connects generics to compile-time safety vs ClassCastException, explains type erasure and its consequences (one runtime class, T erased to its bound), and the static-member restriction.
Frames generics as part of API design — when to make a class generic vs not, naming conventions, interaction with erasure for library evolution, and the cost of leaking raw types into a public API.
## What problem do generics solve? Before generics (Java 5, 2004), a reusable container like a list stored elements as `Object`. You could put anything in, but taking something out required a manual cast, and the compiler could not stop you from putting the wrong thing in: ```java List list = new ArrayList(); list.add("hello"); String s = (String) list.get(0); // cast needed list.add(42); // compiles, but is a logic bug ``` A **generic class** lets you tell the compiler *what type of thing* a class works with, so the compiler enforces it and inserts casts for you. ## Terminology, defined - **Type parameter**: a placeholder name (e.g. `T`) declared by the class for a type that will be supplied later. It lives in angle brackets `<...>` right after the class name. - **Type argument**: the *actual* type you supply when you use the class, e.g. `String` in `Box<String>`. - **Parameterized type**: the result of supplying type arguments, e.g. `Box<String>`. This is the concrete type you actually use in code. - **Generic type / raw type**: `Box` (no arguments) is the *raw type*; using it loses type safety and the compiler warns. ## Declaring a generic class ```java public class Box<T> { // T is the type parameter private T value; // field uses T public void set(T value) { // method parameter uses T this.value = value; } public T get() { // return type uses T return value; } } ``` The `<T>` after `Box` introduces `T` as a name usable anywhere inside the class body where a type is expected. By convention type parameters are single uppercase letters: `T` (type), `E` (element), `K`/`V` (key/value), `N` (number), `R` (result). These are just names; you could write `<Element>` if you wanted. ## Generic interfaces Interfaces work identically: ```java public interface Container<T> { T get(); void put(T item); } ``` A class implementing it either fixes the type (`class StringBox implements Container<String>`) or stays generic (`class GenericBox<T> implements Container<T>`). ## Instantiating a parameterized type ```java Box<String> b = new Box<>(); // diamond operator <> infers String on the right b.set("hi"); String s = b.get(); // no cast: compiler knows it is String b.set(42); // COMPILE ERROR: 42 is not a String ``` The **diamond operator** `<>` (Java 7+) lets you omit the type argument on the right-hand side because the compiler infers it from the variable's declared type. ## What the compiler actually does (type erasure, briefly) Generics are a *compile-time* feature. After the compiler checks your types and inserts casts, it **erases** the type parameters: at runtime `Box<String>` and `Box<Integer>` are both just `Box`, and `T` becomes its bound (here, `Object`). This is called **type erasure**. It means there is exactly one `Box` class at runtime regardless of how many type arguments you used, and you cannot ask an object at runtime which type argument it was created with. ## Multiple type parameters A class can take several type parameters, separated by commas: ```java public class Pair<K, V> { private final K key; private final V value; public Pair(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public V getValue() { return value; } } Pair<String, Integer> p = new Pair<>("age", 30); ``` ## Why it matters Generics give you **compile-time type safety** (mistakes caught while compiling, not as runtime `ClassCastException`s), **eliminated casts** (cleaner code), and **reusable, single implementations** that work for many types. Almost the entire Java Collections Framework is built on generic classes and interfaces.
- Why are the angle brackets on the left of a declaration a 'type parameter' but on the right of a use a 'type argument'?On the left (class Box<T>) you are *introducing* a placeholder name the class is parameterized over — that is the parameter. On the right (Box<String>) you are *supplying* the concrete value for that placeholder — that is the argument. Same parameter-vs-argument distinction as a method's formal parameter vs the value you pass.
- Can a generic class have static fields of type T?No. Type parameters belong to an *instance* (each Box<X> would want its own T), but static members are shared across all instances and all parameterizations, so there is no single T to mean. The compiler rejects static T fields and static methods cannot use the class's type parameter (a static method can declare its own).
saying these in an interview costs you the question
- Confusing the type parameter (declared, e.g. T) with the type argument (supplied, e.g. String)
- Thinking each Box<X> is a separate class at runtime — erasure means there is one Box
- Saying you must repeat the type on the right: new Box<String>() instead of new Box<>()
- Believing generics add runtime overhead or runtime type checks — they are compile-time only