Charbel Charbel - 3 months ago 6x
Java Question

another java generic question

I have the following class:

interface Able{/* ... */}
class A implements Able{/* ... */}

and I have

Map<String,? extends Able> as;
as = new HashMap<String, A>();

why does the following cause an error:

as.put("a", new A());

Any ideas?


The reference to java generics is good (jdk site).

Indeed @Oli_Charlesworth gave a good answer, but maybe this one will be more complete.

In a Collection<? extends Able> you can't insert anything that's right.

If you have

class A implements Able {...}


class B implement Able {...}

Then, Collection<? extends Able> is a super type of both :


Thus it is legal to write some statement like

//Code snippet 01
Collection< ? extends Able > list;
Collection<A> listA;
Collection<B> listB;
list = listA;
list = listB;

That is indeed the reason why the wildcard notation Collection<? extends Able> exists.

But, here things are getting more interesting :

In a Collection<A> you can only insert objects that are A (including subclasses). Same for Collection<B>. In both you can't add something that is just Able. For instance :

//Code snippet 02
listA.add( new A() );  //valid at compile-time
listA.add( new B() );  //not valid at compile-time
listB.add( new B() );  //valid at compile-time
listB.add( new A() );  //not valid at compile-time

Thus, if you group what we saw in code snippets 01 & 02, you will understand that it's absolutely impossible for the compiler to accept a statement like :

Collection< ? extends Able > list;
list.add( new A() );         //not allowed, will work only if list is List<A>
list.add( new B() );         //not allowed, will work only if list is List<B>

So yes, the super type Collection< ? extends Able > doesn't accept to add anything. More general types offer the intersection of functionalities of subtypes, and, as such, less features that subtype. Here, we lose the ability to add A objects and B objects. Those feature will happen later in the hierarchy... and it even means that we can't add anything in the super class Collection< ? extends Able >

Additional remark :

Also, note that in a Collection<Able> you can add whatever you want like this :

Collection< Able > list;
list.add( new A() );         //valid
list.add( new B() );         //valid

But, Collection<Able> is not a superclass of Collection<A> and Collection<B>. It would mean, as with any inheritance relation, that subclasses can do whatever their superclass can do, as inheritance is specialization. So, this would mean that we could add A objects and B objects to both subclasses Collection<A> and Collection<B> and that is not the case. So as it's not a superclass you can't have :

Collection<Able> list;
Collection<A> listA;
Collection<B> listB;
list = listA;  //not valid because there is no inheritance hierarchy
list = listB;  //not valid because there is no inheritance hierarchy

Note that inheritance is a hyperonimic relation (generalization/specialization) and collections define a meronimic relation (container/containee). And it's a headache to combine both of them formally, even though it's somewhat used quite easily by the fuzzy creatures humans are, for instance in the french figure of speech : synecdocque. :)