Middle
How does Java handle generics?
sobes.tech AI
Answer from AI
Java handles generics through type erasure.
During compilation, information about generic types is removed. This means that in bytecode, a class ArrayList<String> and ArrayList<Integer> will look the same - as ArrayList. Instead of generic parameters, the compiler substitutes Object or the upper bound of the bounded type. In places where types are used, the compiler inserts implicit casts.
Advantages of type erasure:
- Compatibility with earlier versions of Java: Code with generics can interact with code written before their introduction, as the bytecode does not contain type information.
- No additional runtime overhead: Since information about generic types is removed, there is no need for type checks at runtime, which can improve performance.
Disadvantages of type erasure:
- Cannot use primitive types as generic parameters: For example,
ArrayList<int>is invalid. You have to use their wrapper classes (ArrayList<Integer>). - Loss of type information at runtime: This can complicate some operations, such as creating an array of a generic type (
new T[size]) or type checking (instanceof).
Example of implicit cast after erasure:
// Creating a generic list
List<String> stringList = new ArrayList<>();
stringList.add("Hello");
// In bytecode, it looks like this (after erasure):
// List stringList = new ArrayList();
// stringList.add("Hello"); // obj.add(java.lang.Object)
// Getting an element from the list
String greeting = stringList.get(0);
// The compiler adds a cast in bytecode:
// String greeting = (String)stringList.get(0);
Bounded wildcards are used for more flexible management of type parameters.
<? extends T>: Represents any type that extends or is T. Allows reading elements as T or its subtypes.<? super T>: Represents any type limited to T or its supertypes. Allows adding elements of type T or its subtypes.
// Example with <? extends>
List<? extends Number> numbers = new ArrayList<Integer>();
Number num = numbers.get(0); // OK
// numbers.add(new Double(1.0)); // Compilation error
// Example with <? super>
List<? super Integer> integers = new ArrayList<Number>();
integers.add(10); // OK
// Integer i = integers.get(0); // Compilation error, returns Object