Readablewiki

Generics in Java

Content sourced from Wikipedia, licensed under CC BY-SA 3.0.

Generics in Java explain how a class or method can operate on objects of different types while keeping the code type-safe at compile time. They were added in Java 5 (J2SE 5.0) to improve safety and reduce the need for casting.

Why generics matter
- Without generics, collections like a list of Object can hold any type. When you take something out and cast it to the wrong type, you get a runtime error. Generics catch type mistakes at compile time.
- With generics, you write things like List or Map. The compiler knows what type is stored and what can be returned, so you don’t need risky casts.

How they work in simple terms
- A type parameter lets a class or method work with any type. For example, List can be a list of Strings, Integers, or any other type.
- The diamond operator (<>), introduced in Java 7, lets the compiler infer the type on the right side: List names = new ArrayList<>();.

Primitives and type safety
- Generics don’t work with primitive types directly (int, double, etc.). You use their wrapper types (Integer, Double) instead.

Type erasure and runtime behavior
- Java uses type erasure: all generic type information is removed at runtime. So List and List are both just List at run time.
- The compiler checks types, but at run time the specific type parameters aren’t available. This keeps backward compatibility and keeps runtime code simpler, but it also means you can’t rely on generic type information being present during execution.

Common differences and rules
- Generics are invariant: List is not a supertype of List. You can’t use a List where a List is expected.
- Arrays are covariant: String[] is a subtype of Object[]. Generics avoid this risk, preventing certain runtime errors.
- Wildcards add flexibility:
- List means “a list of some unknown type.” You can read items as Object but you can’t safely add any specific type (except null).
- List is for reading numbers (you can get Numbers out), but you can’t add arbitrary numbers.
- List allows adding Number or its subtypes, but reading from it gives Object.
- The Producer/Consumer idea (PECS: Producer Extends, Consumer Super) helps decide which wildcard to use.

Practical tips
- Use generics to avoid casts and catch errors early.
- Prefer List instead of List when you know the item type.
- Use the diamond operator to keep code concise.
- When you need flexibility, wildcards help you write methods that work with a range of types without sacrificing safety.

A quick contrast with arrays
- Generics enforce type safety at compile time and are non-reifiable (type information isn’t kept at runtime). Arrays are reifiable and preserve their element type at runtime, but they can lead to runtime errors if misused.
- If you store a Long[] where an Object[] is expected, the compiler won’t complain for arrays, but it would for generics. Generics’ invariance helps prevent such mistakes.

Looking ahead
- Java continues to explore improvements to generics and how they fit with future language features, aiming to make them even more powerful while keeping code safe and predictable.

In short, generics give Java a strong, compile-time type check for collections and other parametric code, reduce casting, and still work smoothly with runtime efficiency thanks to type erasure.


This page was last edited on 2 February 2026, at 21:48 (CET).