Generics and use of extends in HashMap

Discussion in 'Java' started by David Harrigan, Oct 2, 2006.

  1. Hi,

    First the code:

    public interface A {
    }

    public class B implements A {
    }

    public class C {

    public static void main(String[] args) {
    new C().doIt();
    }

    public void doIt() {
    Map<String, ? extends A> a = new HashMap<String, A>();
    a.put("A Test", new B());
    }
    }

    This won't compile, specifically at line "a.put..." because it says (in
    eclipse):

    "The method put(String, capture-of ? extends A) in the type Map<String,
    capture-of ? extends A> is not applicable for the argumentes (String,
    B)"

    Why? I'm confused...

    I thought I was saying that I want a map that takes a key with any
    value that extends (or implements) A, and since B implements A it
    should be happy....

    Why doesn't this work?

    Thanks

    -=david=-
     
    David Harrigan, Oct 2, 2006
    #1
    1. Advertising

  2. David Harrigan

    Chris Brat Guest

    Hi,

    This works in your heirarchy because of normal object conversion ( B to
    A ) - you dont need to specify the ? extends clause.

    Chris



    public void doIt() {
    Map<String, A> a = new HashMap();
    a.put("A Test", new B());
    }
     
    Chris Brat, Oct 2, 2006
    #2
    1. Advertising

  3. David Harrigan

    Chris Brat Guest

    Chris Brat, Oct 2, 2006
    #3
  4. David Harrigan wrote:
    > public interface A {


    > public class B implements A {


    > public void doIt() {
    > Map<String, ? extends A> a = new HashMap<String, A>();
    > a.put("A Test", new B());
    > }


    From Map<String, ? extends A> a, we know all the values of a extend A.
    But there may be further constraints such that not all instances of A
    can be values of a.

    Suppose class C implements A. Then we could have had:

    Map<String, C> map = new HashMap<String, C>();
    Map<String, ? extends A> a = map;
    a.put("A Test", new B()); // ILLEGAL
    C c = map.get("A Test");

    We have assigned a B to a C variable. Oops.

    What you can write is:

    Map<String, ? super A> a = new HashMap<String, A>();

    With a declared as such, it could either be a Map<String,A> or
    Map<String,Object>. So we can definitely add an instance of B
    (implements A). However, when we get an object from the map, we only
    know that it is some kind of Object.

    Tom Hawtin
     
    Thomas Hawtin, Oct 2, 2006
    #4
  5. Thanks Thomas (and others) for your reply:

    I still don't *get* it however.

    If C is implmenting A, then has the same type as B, therefore
    C and B would be of the same type (A), so why would assigning
    B to C cause a problem?

    I read also the <? super A> as "anything who's super is A", so
    why would this be different that <? extends A> as "anything that
    is of type A"?

    -=david=-

    Thomas Hawtin wrote:
    > David Harrigan wrote:
    > > public interface A {

    >
    > > public class B implements A {

    >
    > > public void doIt() {
    > > Map<String, ? extends A> a = new HashMap<String, A>();
    > > a.put("A Test", new B());
    > > }

    >
    > From Map<String, ? extends A> a, we know all the values of a extend A.
    > But there may be further constraints such that not all instances of A
    > can be values of a.
    >
    > Suppose class C implements A. Then we could have had:
    >
    > Map<String, C> map = new HashMap<String, C>();
    > Map<String, ? extends A> a = map;
    > a.put("A Test", new B()); // ILLEGAL
    > C c = map.get("A Test");
    >
    > We have assigned a B to a C variable. Oops.
    >
    > What you can write is:
    >
    > Map<String, ? super A> a = new HashMap<String, A>();
    >
    > With a declared as such, it could either be a Map<String,A> or
    > Map<String,Object>. So we can definitely add an instance of B
    > (implements A). However, when we get an object from the map, we only
    > know that it is some kind of Object.
    >
    > Tom Hawtin
     
    David Harrigan, Oct 2, 2006
    #5
  6. David Harrigan wrote:
    >
    > If C is implmenting A, then has the same type as B, therefore
    > C and B would be of the same type (A), so why would assigning
    > B to C cause a problem?


    An instance of C has type C and an instance of B has a type B. You can't
    have a reference of type C referencing a B, or vice versa. A reference
    of type A can reference either B or C. Suppose A was not abstract, then
    a reference of type B or C could not reference an instance of type A.

    > I read also the <? super A> as "anything who's super is A", so
    > why would this be different that <? extends A> as "anything that
    > is of type A"?


    "Anything that is a super of A." T super MyType, means that T is a
    supertype of MyType. T extends MyType means that T is a subtype of
    MyType. They aren't the best keywords in the world, but there was a
    desire not to add any extra.

    Tom Hawtin
     
    Thomas Hawtin, Oct 2, 2006
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jon Skeet
    Replies:
    5
    Views:
    2,194
    Dale King
    Jul 8, 2003
  2. Vince Darley
    Replies:
    4
    Views:
    4,564
    emilchacko
    Mar 2, 2010
  3. hiwa
    Replies:
    7
    Views:
    1,353
    Chris Uppal
    Feb 12, 2005
  4. odwl
    Replies:
    1
    Views:
    12,285
    Thomas Hawtin
    Jun 15, 2006
  5. Rakesh
    Replies:
    10
    Views:
    12,273
    Mike Schilling
    Apr 8, 2008
Loading...

Share This Page