4.B] Write a note on:
i) Bounded Wildcards
ii) Erasure
Answer:
i) Bounded Wildcards
Bounded Wildcards in Java generics are a way to restrict the types that can be passed as arguments to a generic method or class.
They allow you to specify an upper or lower bound for the type parameter, making the code more flexible while still enforcing some type safety.
Types of Bounded Wildcards:
- Upper Bounded Wildcards (
<? extends T>
):
- Restricts the type to be a subtype of
T
. - Useful when you want to read from a generic structure but not modify it.
- Example:
List<? extends Number>
means the list can hold objects of typeNumber
or its subclasses likeInteger
,Double
, etc. Example:
public static void printNumbers(List<? extends Number> list) { for (Number num : list) { System.out.println(num); } }
- Lower Bounded Wildcards (
<? super T>
):
- Restricts the type to be a supertype of
T
. - Useful when you want to write to a generic structure but not read from it.
- Example:
List<? super Integer>
means the list can holdInteger
and any of its supertypes likeNumber
orObject
. Example:
public static void addNumbers(List<? super Integer> list) { list.add(10); list.add(20); }
Summary: Bounded wildcards are a powerful feature in Java generics that provide more control over what types can be used in generic classes and methods. They enhance flexibility while maintaining type safety.
ii) Erasure
Type Erasure is the process by which the Java compiler removes generic type information during the compilation of code.
This means that after compilation, the bytecode contains only non-generic versions of classes, methods, and interfaces. This process ensures backward compatibility with older versions of Java that did not support generics.
How Erasure Works:
- Replace Type Parameters: During compilation, the compiler replaces all generic type parameters with their bound types (or
Object
if no bound is specified). For example,List<T>
might becomeList<Object>
. - Insert Casts: Where necessary, the compiler inserts type casts to ensure type safety. For instance, when retrieving elements from a generic collection, it adds the appropriate cast to convert the object back to the expected type.
- Remove Generic Information: Finally, the compiler removes all generic type information from the compiled bytecode, meaning the runtime has no knowledge of the generic types.
Example Before Erasure:
public class Box<T> { private T value; public void set(T value) { this.value = value; } public T get() { return value; } }
Example After Erasure:
public class Box { private Object value; public void set(Object value) { this.value = value; } public Object get() { return value; } }
Implications of Erasure:
- No Runtime Type Information: Because type information is erased, you cannot perform certain operations at runtime, such as checking the type of a generic parameter (
if (obj instanceof T)
is not allowed). - Type Safety via Casts: The compiler adds type casts where necessary, but this can lead to
ClassCastException
at runtime if the code is not used correctly. - Overloading Restrictions: Since type erasure removes generic information, methods that differ only by generic type parameters cannot be overloaded. For example,
void print(List<String> list)
andvoid print(List<Integer> list)
cannot coexist.
Summary: Type erasure ensures that generics are a compile-time feature in Java, providing backward compatibility while also maintaining type safety. However, it introduces some limitations, such as the loss of type information at runtime.