JavaGenericsintermediate
Updated:

Java Generics Interview Questions and Answers

5 min read

The generics questions Java interviews rely on — type erasure, wildcards, the PECS rule, bounded type parameters and generic methods — answered with clear code.

TL;DR – Quick Answer

Generics interviews test whether you understand compile-time type safety and its limits: how type erasure works, why you cannot create a generic array or check a generic type at runtime, bounded type parameters, wildcards and the PECS rule for choosing extends versus super. Interviewers grade you on erasure — it explains almost every generics restriction and error you will meet.

On This Page

Why generics questions reveal your depth

Generics look like a syntax topic and are actually a mental-model topic. Almost every generics question — why you cannot create new T[], why List<String> is not a List<Object>, when to write ? extends — traces back to one idea: type erasure. Interviewers ask about generics because the candidates who understand erasure can explain the restrictions instead of memorizing them, and that reasoning transfers directly to writing safe APIs.

This page covers the generics questions asked most, built up from erasure. Because generics underpin lambdas and functional types, pair it with the lambda expressions questions and functional interfaces set.

Q1. Why were generics added, and what do they give you?

Generics provide compile-time type safety and eliminate casts. Before generics, a List held Object, so you cast on every read and could accidentally store the wrong type, failing at runtime. With List<String>, the compiler enforces the element type and inserts no-cast reads — errors move from runtime to compile time.

The one-sentence value is "move type errors from runtime to compile time." A good follow-up answer notes that generics also make APIs self-documenting: Map<UserId, Order> states intent that Map alone hides. This framing shows you value generics for correctness, not decoration.

Q2. What is type erasure?

The compiler uses generic type information to check your code, then erases it — replacing each type parameter with its bound (or Object if unbounded) and inserting casts where needed. So List<String> and List<Integer> compile down to the same raw List; no type-argument information survives to runtime.

List<String> strings = new ArrayList<>();
List<Integer> ints = new ArrayList<>();
System.out.println(strings.getClass() == ints.getClass()); // true — both just ArrayList

Erasure is the single fact that explains the rest of the topic. Its consequence chain: no instanceof List<String>, no new T[], no two overloads differing only by type argument, and no runtime access to the type parameter. Being able to derive those restrictions from erasure is exactly what interviewers reward.

Q3. What are bounded type parameters?

A bound restricts a type parameter to a type or its subtypes using extends: <T extends Number> means T can be Number or any subclass, which lets you call Number's methods on T. You can specify multiple bounds with &, and the first bound may be a class while the rest are interfaces.

// Bound lets us call doubleValue(); without it, T would only offer Object's methods
static <T extends Number & Comparable<T>> T max(T a, T b) {
    return a.compareTo(b) >= 0 ? a : b;
}

The reason bounds matter: an unbounded T is erased to Object, so you can only call Object methods on it. Bounding to Number erases T to Number, unlocking its API. Connecting bounds to what erasure does is the deeper answer.

Q4. Explain wildcards and the PECS rule.

A wildcard ? represents an unknown type. ? extends T is an upper-bounded wildcard — a producer you read T from but cannot write to. ? super T is a lower-bounded wildcard — a consumer you write T into but read back only as Object. PECS: Producer Extends, Consumer Super.

// Copies from a producer (extends) into a consumer (super)
static <T> void copy(List<? extends T> src, List<? super T> dst) {
    for (T item : src) dst.add(item);
}

Why the asymmetry exists: from a List<? extends Number> you know every element is a Number, so reading is safe, but you cannot add because the exact type is unknown. Into a List<? super Integer> you can safely add Integers, but a read only guarantees Object. Deriving PECS from what is provably safe — rather than reciting the acronym — is the senior answer.

Q5. Why can't you create a generic array?

Arrays are covariant and enforce their element type at runtime (ArrayStoreException), while generics are erased and enforced only at compile time. If new List<String>[] were allowed, erasure would hide the type argument from the array's runtime check, letting a List<Integer> be stored where List<String> was expected — defeating type safety.

// List<String>[] arr = new List<String>[10]; // compile error: generic array creation
List<String>[] arr = (List<String>[]) new List[10]; // legal but unchecked, discouraged

The clean summary: arrays know their type at runtime; generics forget theirs. Mixing a runtime-checked, covariant construct with a compile-time-only one is unsafe, so the language forbids generic array creation. This is a favorite because it forces you to hold both erasure and array covariance in mind at once.

Q6. What is the difference between List, List<?> and a raw List?

List<Object> explicitly holds any Object and you can add to it. List<?> is a list of some unknown type — you cannot add anything but null, though you can read as Object. A raw List opts out of generics entirely, disabling type checking and generating unchecked warnings; it exists only for backward compatibility.

The trap is thinking List<String> is a List<Object> — it is not, because generics are invariant. List<?> is the correct type for "a list of some type I do not need to name," typically as a read-only or size-only parameter. Using a raw type is almost always a bug or legacy interop.

Q7. Can you write a generic method, and how does inference work?

Yes — a method can declare its own type parameters before the return type, independent of the class. The compiler infers the type arguments from the call site, so you rarely specify them explicitly. This is how utility methods stay type-safe across many types.

static <T> List<T> firstTwo(T a, T b) {   // <T> declared before return type
    return List.of(a, b);
}
List<String> names = firstTwo("a", "b");  // T inferred as String

Mention that you can supply the type witness explicitly (Util.<String>firstTwo(...)) when inference cannot decide, and that generic methods are why Collections.emptyList() returns the right type without a cast. Inference plus erasure together explain most of generics' everyday ergonomics.

Q8. What are common generics mistakes interviewers watch for?

Using raw types and ignoring unchecked warnings; assuming List<String> is assignable to List<Object>; trying instanceof with a parameterized type; choosing the wrong wildcard direction; and creating generic arrays via unchecked casts without understanding the risk. Each traces back to forgetting erasure or invariance.

The strongest close is to tie the mistakes together: they all come from treating generics as if the type survives to runtime, or as if generic types were covariant like arrays. An engineer who names erasure and invariance as the two root causes has demonstrated they understand the topic rather than a checklist.

How to prepare

Make erasure your anchor: once you can derive "no generic arrays, no runtime type checks, no overload-by-type-argument, PECS" from erasure and invariance, you can answer questions you have never seen. Write the demos — the identical getClass(), the PECS copy method, the generic-array compile error — because seeing the compiler reject them fixes the rules in memory. Then connect generics forward to the lambda expressions questions and functional interfaces set, where generic functional types like Function<T,R> appear constantly, and rehearse the PECS derivation aloud in a mock interview.

Frequently Asked Questions

What is type erasure in Java generics?
Type erasure means generic type information exists only at compile time; the compiler checks types, then removes them, replacing type parameters with their bounds (or Object). At runtime a List<String> and a List<Integer> are both just List, which is why you cannot query the type argument at runtime.
What is the PECS rule?
PECS stands for 'Producer Extends, Consumer Super.' Use '? extends T' when a structure produces T values you read out, and '? super T' when it consumes T values you put in. It tells you which wildcard to choose based on whether you read from or write to the collection.
Why can't you create an array of a generic type?
Arrays are covariant and check their element type at runtime, but generics are erased and checked only at compile time. Allowing generic arrays would let type errors slip past the runtime array check, so 'new T[]' and 'new List<String>[]' are disallowed by the compiler.
What is the difference between List<Object> and List<?>?
List<Object> is a list you can add any Object to. List<?> is a list of some unknown type, so you cannot add anything to it except null, because the compiler cannot guarantee the element type — but you can read elements as Object.
Are generics only a compile-time feature?
Yes. Generics provide compile-time type checking and remove casts, but because of erasure they add no runtime type information. This is why you cannot use instanceof with a parameterized type or overload methods that differ only by type argument.

Want to Build Your Career in Java Full Stack with AI?

Join CodeBegun and train with working industry engineers — Explore the Java Full Stack program

Apply for Demo Class →
Siva Prasad Galaba
Founder, CodeBegun · Staff Engineer

Founder of CodeBegun. 15+ years building Java systems at companies like Crunchyroll. Teaches Java, Spring Boot and system design the way the industry actually works, and mentors students through projects, mock interviews and placement preparation.

Technically reviewed by CodeBegun Technical TeamLast reviewed 16 July 2026 LinkedIn