Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
138 views
in Technique[技术] by (71.8m points)

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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 {...}

and

class B implement Able {...}

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

Collection<A>
Collection<B>

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. :)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...