3

I've read that when you define a {Map, Set, Etc} it is good practice use the interface name as so:

Map<Integer, String> map = new LinkedHashMap<Integer, String>();

instead of:

LinkedHashMap<Integer, String> map = new LinkedHashMap<Integer, String>();

I'm not sure why this is, but I've put it to practice in hopes I will understand at a later time. Maybe that time has come.

So I create a class that defines one and create a getter for the Map:

class Data{

    private Map<Integer, String> map;

    public Data(){
        map = new LinkedHashMap<Integer, String>();
        //dynamically put some things into the map
    }

    public Map<Integer, String> getMap(){
        return map;
    }

}

Now I come to my first impasse. I can't return a LinkedHashMap, I have to return a Map. So in another class I get that Map

class Foo{

    public Foo{
        Data data = new Data();
        Map<Integer, String> map = data.getMap();
    }

}

  • Can someone explain what is happening to map when it gets passed?
  • Is it still a LinkedHashMap?
  • Is the data changed at all?
  • What would happen to the order of the Map if, after calling getData(), I put something in the Map?
  • Why wouldn't/shouldn't I just define the Map as in the second code snippet?
    Is my method of getting the map done in ignorance?
  • Should I just make map public?
  • Jorge Campos
    • 22,647
    • 7
    • 56
    • 87
    patterned
    • 424
    • 3
    • 9

    2 Answers2

    1

    Now I come to my first impasse. I can't return a LinkedHashMap

    Here's the misunderstanding: you can return a LinkedHashMap, because a LinkedHashMap is a Map, a particular sort of Map, but a Map anyway.

    Can someone explain what is happening to map when it gets passed?

    When it's passed, it is seen as any Map, like incognito, but it remains the same.

    Is it still a LinkedHashMap?

    Yes.

    Is the data changed at all?

    No.

    What would happen to the order of the Map if, after calling getData(), I put something in the Map?

    This is another topic.

    Why wouldn't/shouldn't I just define the Map as in the second code snippet?

    You needn't do that, since a LinkedHashMap is a Map (on the other hand, a Map is not necessarily a LinkedHashMap).

    Is my method of getting the map done in ignorance? Should I just make map public?

    No.

    Bludzee
    • 2,733
    • 5
    • 38
    • 46
    • Eclipse balks at me: "Type mismatch: cannot convert from Map to LinkedHashMap". I can cast it to a LinkedHashMap.. but that still leave me scratching my head as to why I would define it as `Map` instead of `LinkedHashMap` – patterned Jan 14 '14 at 15:58
    • @patterned That doesn't make sense. Are you sure this error occurs in `getMap()`, or in some other code *using* `getMap()`? – Mattias Buelens Jan 14 '14 at 16:00
    • It's in getMap(). Eclipse underscores the object `map` in this line: `return map;` and gives that error. `public LinkedHashMap getMap(){ return map; }` – patterned Jan 14 '14 at 16:04
    • @patterned `getMap()` should return a `Map` and **not** a `LinkedHashMap`. That is the whole point. – Boris the Spider Jan 14 '14 at 16:31
    • @BoristheSpider I get that, but I'm trying to understand why. And it seems he is arguing that I **can** return a `LinkedHashMap` without casting. – patterned Jan 14 '14 at 16:33
    • 1
      @patterned There's a difference between the *return type of a method* and the *type of the returned value*. If `map` is of type `LinkedHashMap`, then you *can* use it as return value for a method with return type `Map`. However, if `map` is of type `Map`, then you *cannot* use it for a method with return type `LinkedHashMap`. – Mattias Buelens Jan 14 '14 at 16:40
    • @MattiasBuelens Ok, thanks. I thought he was trying to argue otherwise. So, what would be the proper way to put more values in `map` from outside the class and still maintain a `LinkedHashMap`? Create a setter and then `map.put(foo,bar)`? Or would you have to cast it? – patterned Jan 14 '14 at 16:49
    • 1
      @patterned The whole point about interfaces is that *you don't need to know the concrete implementation* when you're using an implementing object. That's what polymorphism is all about! Your class can use whatever `Map` implementation it likes: `HashMap`, `LinkedHashMap`, `TreeMap`,... and just return it in `getMap()` as a `Map`. Whenever someone calls a `Map` method (e.g. `getMap().put(5, "foo")`), it will be *dispatched* to the actual implementation. Seriously, [read a tutorial](http://docs.oracle.com/javase/tutorial/java/IandI/polymorphism.html)! – Mattias Buelens Jan 14 '14 at 16:57
    • @MattiasBuelens Thank you. That last message was exactly what I was looking for!! – patterned Jan 14 '14 at 17:03
    0

    You may want your variable to be able do what it needs to do and still be as flexible as possible in the way it does that. So your variable should be of the type that covers all your needed functionality but is as high as possible in hirachy.

    Yannic Welle
    • 207
    • 2
    • 10