Background:
Generics in Java were introduced in Java 5 to ensure safe operation with collection types and methods, but they were implemented with backward compatibility in mind for previously written bytecode. This was achieved using the type erasure mechanism.
Problem:
The Java compiler requires strict typing, but at runtime, the JVM does not know about the type parameters, and many old classes and libraries, including Java's own collection library, work with raw types. Without backward compatibility, it would have been impossible to support existing developments.
Solution:
Type erasure is the process of converting parameterized types (generics) to their raw versions so that the JVM can work with already existing bytecode without changes. All information about type parameters is removed at compile time, and instead, Object (or a bound if specified via extends) is used.
Example code:
List<String> stringList = new ArrayList<>(); stringList.add("hello"); String s = stringList.get(0); // get returns Object, but the compiler inserts a cast
Key features:
List<String>, List<Integer>, etc.Can method overloading be used only based on generic parameters?
No. Due to type erasure, the compiler considers methods with the same name and different generic parameter types as identical, since the parameters will be erased. For example,
// Compilation error! void process(List<String> list) { } void process(List<Integer> list) { }
Can an array of a generic type be created?
No, not directly. Type erasure does not allow the JVM to hold an array of a specific generic type, for example,
List<String>[] array = new List<String>[10]; // Compilation error
It can be circumvented using an array of raw types, but it is unsafe:
List<String>[] array = (List<String>[]) new List[10];
Can the type of a generic be checked at runtime using instanceof?
No, because the information about parameters is erased. The check:
if (obj instanceof List<String>) { ... } // Compilation error
It is more accurate to check only the base type:
if (obj instanceof List) { ... }
A programmer creates an array of parameterized types to store lists of different parameters. Eventually, after a lengthy execution of the program, a ClassCastException occurs when retrieving an object from the array — typing at runtime is not enforced.
Pros:
Cons:
Instead of arrays, collections (e.g., List<List<String>>) are used, and all type checks are delegated to the compiler.
Pros:
Cons: