skip to content

Generic Fundamentals

Declaring generic classes, interfaces, methods and constructors, and the syntax of type parameters. The starting point for any question about writing your own generic API.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

15

What is a generic class in Java, and how do you declare one with a type parameter?

level: juniorimportance: must knowfreq 85%

answer

  1. Type parameter in <> after the class name: class Box<T>
  2. T usable in fields, params, return types
  3. Type argument supplied at use: Box<String> (parameterized type)
  4. Diamond <> infers the argument
  5. Erasure: one class at runtime, T becomes its bound

basics

~20 s

A 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 s

A 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

for a junior

Can declare class Box<T>, use T for a field and a get/set method, and instantiate Box<String> with the diamond operator.

for a middle

Explains the type parameter vs type argument distinction, multiple parameters (Pair<K,V>), generic interfaces, and that raw types lose safety.

for a senior

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.

for a principal

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

context

open as a page

How do you declare a generic method in Java, and where does the type-parameter section go?

level: juniorimportance: must knowfreq 78%

basics

~20 s

You put the type parameters in angle brackets right before the return type, e.g. static <T> T pick(T a, T b). That <T> introduces a name you can then use for the parameters and return type.

open as a page

What is the diamond operator (<>) introduced in Java 7, and how does it work?

level: juniorimportance: must knowfreq 70%

basics

~20 s

The diamond operator is the empty angle brackets <> used on the right side of an assignment. It tells the compiler to infer the generic type arguments from the left side, so you don't repeat them. Example: List<String> list = new ArrayList<>();

open as a page

What is type-argument inference at a call site, and when do you need an explicit type witness?

level: middleimportance: must knowfreq 62%

basics

~20 s

The compiler usually figures out the type from the arguments, so you just call the method normally. When it can't (e.g. no arguments to look at), you write the type explicitly before the method name, like Collections.<String>emptyList().

open as a page

What are the conventional single-letter names for Java generic type parameters (T, E, K, V, N), and why do these conventions matter?

level: juniorimportance: should knowfreq 55%

basics

~20 s

They are agreed-on short names for generic type parameters: T means a general Type, E an Element (collections), K a Key and V a Value (maps), N a Number. They are just naming conventions that make code easier to read.

open as a page

How do you declare and use a generic class with multiple type parameters, and how does it differ from a generic interface like Map<K,V>?

level: middleimportance: should knowfreq 62%

basics

~20 s

List several type parameters in the angle brackets separated by commas, like class Pair<K, V>. Each one is an independent placeholder you can use for fields, parameters, and return types. A generic interface such as Map<K,V> is the same idea but for an interface — implementing classes supply or pass along those types.

open as a page

What is the difference between a raw type, a parameterized type, and Box<Object>, and why does using a raw type defeat the purpose of generics?

level: middleimportance: should knowfreq 55%

basics

~20 s

A raw type is using a generic class with no type argument, like Box. A parameterized type supplies one, like Box<String>. A raw Box turns off generic type checking and forces casts, bringing back the runtime errors generics were meant to prevent, so the compiler warns against it. Box<Object> still keeps type checking on.

open as a page

How do you declare a generic class or method with multiple type parameters, and how are they bound to actual types?

level: middleimportance: should knowfreq 50%

basics

~10 s

Put several comma-separated placeholders in the angle brackets, like class Pair<K,V> or <T,R> R map(T in). Each placeholder is filled independently when you use the class or call the method, e.g. Pair<String,Integer>.

open as a page

Given type erasure, why can't a generic class have a static field of its type parameter or use that parameter in a static method?

level: seniorimportance: should knowfreq 48%

basics

~20 s

A type parameter belongs to an instance — each object can have a different actual type. Static members are shared by all instances and all parameterizations at once, so there is no single type the parameter could mean. The compiler therefore forbids static fields or static methods that use the class's type parameter.

open as a page

What is a generic constructor, and how are its type parameters independent of the enclosing class's?

level: seniorimportance: should knowfreq 34%

basics

~20 s

A constructor can declare its own type parameters in angle brackets before the constructor name, separate from the class's type parameters. So even a class that isn't generic can have a constructor that takes a generic argument.

open as a page

When should you use a generic method with a type parameter instead of a method that takes a wildcard argument?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Use a named type parameter (<T>) when you need to relate two things — like returning the same type you receive, or linking two arguments. Use a wildcard (?) when you only consume the argument and don't need to name its type anywhere else.

open as a page

When should you introduce a type parameter on a method (a generic method) rather than on the whole class, and how does inference make it ergonomic?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Use a generic method when only one method needs the placeholder type and the class itself doesn't store it. Declare the type parameter before the return type, and callers usually don't have to pass it because the compiler infers it from the arguments.

open as a page

How does type erasure affect generic methods, and why can a static generic method declare its own type parameter while a static field cannot use the class's?

level: principalimportance: should knowfreq 28%

basics

~20 s

Java removes generic type info at compile time (erasure), so at runtime a generic method's T is just Object (or its bound). A static method can declare its own <T> because that type is per-call, but a static field can't use the class's <T> because static members aren't tied to any instance's type.

open as a page

Why couldn't the diamond operator originally be used with anonymous classes, and what changed in Java 9?

level: seniorimportance: nice to knowfreq 30%

basics

~20 s

In Java 7-8 you couldn't write the diamond <> when creating an anonymous class, because the compiler couldn't always name the inferred type for the hidden subclass it generates. Java 9 relaxed this: it now allows <> with anonymous classes whenever the inferred type can be expressed.

open as a page

When designing a public API, how do you decide whether a class should be generic, and what are the long-term consequences of that choice under type erasure?

level: principalimportance: nice to knowfreq 28%

basics

~20 s

Make a class generic when it genuinely works with a caller-chosen type that should flow through its API without casts, like a container. Avoid it when the type is fixed or only one method needs it. Because Java erases generics, once a type is public it is hard to change later without breaking callers.

open as a page