Skip to content

java generic #70

@zero2hj

Description

@zero2hj

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 of Parent[]
  • Generics: List<Sub> is NOT a subtype of List<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 list

Why 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

  1. Generics are invariant - List<Sub> is not a List<Parent>
  2. Wildcards provide flexibility:
    • ? extends for read-only (covariant) access
    • ? super for write-only (contravariant) access
  3. Arrays behave differently - they're covariant but unsafe
  4. 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

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions