-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
Why You Can't Assign List<Sub> to List<Parent> in Java
This is a fundamental aspect of Java generics known as invariance, which often confuses developers coming from languages with covariant arrays or different generic behavior.
The Core Problem
Given:
class Parent {}
class Sub extends Parent {}You might expect this to work:
List<Sub> subs = new ArrayList<>();
List<Parent> parents = subs; // Compile error!But it produces a compile-time error.
Reasons This Isn't Allowed
1. Type Safety Violation Potential
If it were allowed, you could do this:
List<Sub> subs = new ArrayList<>();
List<Parent> parents = subs; // Suppose this worked
parents.add(new Parent()); // Adding Parent to List<Sub>!
Sub s = subs.get(0); // ClassCastException!This would break the type safety guarantees of generics.
2. Generics Are Invariant
Unlike arrays (which are covariant), generics in Java are invariant:
- Arrays:
Sub[]is a subtype ofParent[] - Generics:
List<Sub>is NOT a subtype ofList<Parent>
Solutions and Workarounds
1. Wildcards for Covariance (Read-Only)
List<Sub> subs = new ArrayList<>();
List<? extends Parent> parents = subs; // OK
// Can read as Parent
Parent p = parents.get(0);
// Cannot add (compile error)
parents.add(new Parent());
parents.add(new Sub()); 2. Wildcards for Contravariance (Write-Only)
List<Parent> parents = new ArrayList<>();
List<? super Sub> subs = parents; // OK
// Can add Sub and its subtypes
subs.add(new Sub());
// Can only read as Object
Object o = subs.get(0); 3. Create a New List (Copy)
List<Sub> subs = new ArrayList<>();
List<Parent> parents = new ArrayList<>(subs); // OK, creates new listWhy Arrays Allow This (But Are Dangerous)
Arrays are covariant:
Sub[] subs = new Sub[10];
Parent[] parents = subs; // Compiles!
parents[0] = new Parent(); // Runtime ArrayStoreException!This was allowed for historical reasons (pre-generics) but can cause runtime errors.
Key Takeaways
- Generics are invariant -
List<Sub>is not aList<Parent> - Wildcards provide flexibility:
? extendsfor read-only (covariant) access? superfor write-only (contravariant) access
- Arrays behave differently - they're covariant but unsafe
- Type safety is maintained at compile time for generics
This design prevents subtle bugs that could otherwise occur when collections are treated as covariant while still allowing modification operations.
Metadata
Metadata
Assignees
Labels
No labels