TheLQ
TheLQ

Reputation: 15008

Can't cast generic sets?

I'm ran into an interesting issue today. Consider the following code

public static class Parent {}
public static class Child extends Parent {}

Set<Child> childs = new HashSet();
Set<Parent> parents = (Set<Parent>)childs; //Error: inconvertible types

Parent parent = (Parent)new Child(); //works?!

Why wouldn't a cast like that work? I would expect that an implicit cast wouldn't work due to the various rules of generics, but why can't an explicit cast work?

Upvotes: 4

Views: 6901

Answers (4)

Snicolas
Snicolas

Reputation: 38168

Though, the super type of generics work a bit differently :

Set<Child> childs = new HashSet();
Set<? extends Parent> parents = childs;

Set is the super type of set and Set

I recommend you read this docs about generics to understand that there is no inheritance between generic container just because it is not inheritance. Inheritance, before all, means specialization. Think of a box designed to hold animals, ok it could be derived by a box containing only tigers but then it would mean that box could do for tigers, of course, but also do all what the super type can do, including beeing a good box for all animals. There is something very messy for humans to think about both types of taxonomy : hyperonimic hierarchy (specialization, inheritance) and meronymic hierarchy (container/contained).

In your last line, no need to cast neither :

Parent parent = new Child(); 

Stéphane

Upvotes: 1

Matt Ball
Matt Ball

Reputation: 359786

The cast doesn't work because Java generics are not covariant.

If the compiler allowed this:

List<Child> children = new ArrayList();
List<Parent> parents = (List<Parent>)children;

then what would happen in this case?

parents.add(new Parent());
Child c = children.get(0);

The last line would attempt to assign Parent to a Child — but a Parent is not a Child!

All Child are Parent (since Child extends Parent) but all Parent are not Child.

Upvotes: 18

Rob Raisch
Rob Raisch

Reputation: 17357

Because a Set of Childs(sic) isn't a Set of Parents. Defining a generic (parameterized) Set is effectively the same thing as defining a new class so you're defining two disjoint classes.

Upvotes: 1

fgb
fgb

Reputation: 18569

A Set<Parent> can contain any subclass of Parent. A Set<Child> can contain any subclass of Child. So a subclass of Parent that isn't a subclass of Child would be allowed in one but not the other, making them incompatible types.

Upvotes: 1

Related Questions