What is the difference between the following maps I create (in another question, people answered using them seemingly interchangeably and I'm wondering if/how they are different):
HashMap<String, Object> map = new HashMap<String, Object>();
Map<String, Object> map = new HashMap<String, Object>();
HashMap is an implementation of Map so it's quite the same but has "clone()" method as i see in reference guide))
There is no difference between the objects; you have a
HashMap<String, Object>
in both cases. There is a difference in the interface you have to the object. In the first case, the interface isHashMap<String, Object>
, whereas in the second it'sMap<String, Object>
. But the underlying object is the same.The advantage to using
Map<String, Object>
is that you can change the underlying object to be a different kind of map without breaking your contract with any code that's using it. If you declare it asHashMap<String, Object>
, you have to change your contract if you want to change the underlying implementation.Example: Let's say I write this class:
The class has a couple of internal maps of string->object which it shares (via accessor methods) with subclasses. Let's say I write it with
HashMap
s to start with because I think that's the appropriate structure to use when writing the class.Later, Mary writes code subclassing it. She has something she needs to do with both
things
andmoreThings
, so naturally she puts that in a common method, and she uses the same type I used ongetThings
/getMoreThings
when defining her method:Later, I decide that actually, it's better if I use
TreeMap
instead ofHashMap
inFoo
. I updateFoo
, changingHashMap
toTreeMap
. Now,SpecialFoo
doesn't compile anymore, because I've broken the contract:Foo
used to say it providedHashMap
s, but now it's providingTreeMaps
instead. So we have to fixSpecialFoo
now (and this kind of thing can ripple through a codebase).Unless I had a really good reason for sharing that my implementation was using a
HashMap
(and that does happen), what I should have done was declaregetThings
andgetMoreThings
as just returningMap<String, Object>
without being any more specific than that. In fact, barring a good reason to do something else, even withinFoo
I should probably declarethings
andmoreThings
asMap
, notHashMap
/TreeMap
:Note how I'm now using
Map<String, Object>
everywhere I can, only being specific when I create the actual objects.If I had done that, then Mary would have done this:
...and changing
Foo
wouldn't have madeSpecialFoo
stop compiling.Interfaces (and base classes) let us reveal only as much as is necessary, keeping our flexibility under the covers to make changes as appropriate. In general, we want to have our references be as basic as possible. If we don't need to know it's a
HashMap
, just call it aMap
.This isn't a blind rule, but in general, coding to the most general interface is going to be less brittle than coding to something more specific. If I'd remembered that, I wouldn't have created a
Foo
that set Mary up for failure withSpecialFoo
. If Mary had remembered that, then even though I messed upFoo
, she would have declared her private method withMap
instead ofHashMap
and my changingFoo
's contract wouldn't have impacted her code.Sometimes you can't do that, sometimes you have to be specific. But unless you have a reason to be, err toward the least-specific interface.
Map is an interface that HashMap implements. The difference is that in the second implementation your reference to the HashMap will only allow the use of functions defined in the Map interface, while the first will allow the use of any public functions in HashMap (which includes the Map interface).
It will probably make more sense if you read Sun's interface tutorial
First of all
Map
is an interface it has different implementation like -HashMap
,TreeHashMap
,LinkedHashMap
etc. Interface works like a super class for the implementing class. So according to OOP's rule any concrete class that implementsMap
is aMap
also. That means we can assign/put anyHashMap
type variable to aMap
type variable without any type of casting.In this case we can assign
map1
tomap2
without any casting or any losing of data -As noted by TJ Crowder and Adamski, one reference is to an interface, the other to a specific implementation of the interface. According to Joshua Block, you should always attempt to code to interfaces, to allow you to better handle changes to underlying implementation - i.e. if HashMap suddenly was not ideal for your solution and you needed to change the map implementation, you could still use the Map interface, and change the instantiation type.
Map having following implementations,
HashMap
Map m = new HashMap();
LinkedHashMap
Map m = new LinkedHashMap();
Tree Map
Map m = new TreeMap();
WeakHashMap
Map m = new WeakHashMap();
Suppose you have created one method (It's just spudo code).
Suppose you project requirement are changing each time as follows,
HashMap
.HashMap
toLinkedHashMap
.LinkedHashMap
toTreeMap
.If your method returning Specific classes instead of
Map
interface you have to change return type ofgetMap()
method each time.But, If you use polymorphism feature of java, Instead of returning specific class used interface
Map
, It leads code reusability and less impact if any requirement change.