Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between the HashMap and Map objects in Java?

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>(); 
like image 877
Tony Stark Avatar asked Aug 28 '09 16:08

Tony Stark


People also ask

Is a HashMap the same as an object?

JavaScript Objects: Similar but Different The key in a hashmap can be any datatype, this includes arrays and objects. Meanwhile, objects can only use integers, strings, and symbols as their keys. Hashmaps are organized as linked lists, so the order of its elements is maintained, which allows the hashmap to be iterable.

What is Java Map HashMap?

HashMap<K, V> is a part of Java's collection since Java 1.2. This class is found in java. util package. It provides the basic implementation of the Map interface of Java. It stores the data in (Key, Value) pairs, and you can access them by an index of another type (e.g. an Integer).

What is Java Map object?

A Map is an object that maps keys to values. A map cannot contain duplicate keys: Each key can map to at most one value. It models the mathematical function abstraction.

What is difference between HashMap and HashTable?

HashMap is non-syncronized and is not thread safe while HashTable is thread safe and is synchronized. HashMap allows one null key and values can be null whereas HashTable doesn't allow null key or value. HashMap is faster than HashTable. HashMap iterator is fail-safe where HashTable iterator is not fail-safe.


2 Answers

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 is HashMap<String, Object>, whereas in the second it's Map<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 as HashMap<String, Object>, you have to change your contract if you want to change the underlying implementation.


Example: Let's say I write this class:

class Foo {     private HashMap<String, Object> things;     private HashMap<String, Object> moreThings;      protected HashMap<String, Object> getThings() {         return this.things;     }      protected HashMap<String, Object> getMoreThings() {         return this.moreThings;     }      public Foo() {         this.things = new HashMap<String, Object>();         this.moreThings = new HashMap<String, Object>();     }      // ...more... } 

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 HashMaps 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 and moreThings, so naturally she puts that in a common method, and she uses the same type I used on getThings/getMoreThings when defining her method:

class SpecialFoo extends Foo {     private void doSomething(HashMap<String, Object> t) {         // ...     }      public void whatever() {         this.doSomething(this.getThings());         this.doSomething(this.getMoreThings());     }      // ...more... } 

Later, I decide that actually, it's better if I use TreeMap instead of HashMap in Foo. I update Foo, changing HashMap to TreeMap. Now, SpecialFoo doesn't compile anymore, because I've broken the contract: Foo used to say it provided HashMaps, but now it's providing TreeMaps instead. So we have to fix SpecialFoo 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 declare getThings and getMoreThings as just returning Map<String, Object> without being any more specific than that. In fact, barring a good reason to do something else, even within Foo I should probably declare things and moreThings as Map, not HashMap/TreeMap:

class Foo {     private Map<String, Object> things;             // <== Changed     private Map<String, Object> moreThings;         // <== Changed      protected Map<String, Object> getThings() {     // <== Changed         return this.things;     }      protected Map<String, Object> getMoreThings() { // <== Changed         return this.moreThings;     }      public Foo() {         this.things = new HashMap<String, Object>();         this.moreThings = new HashMap<String, Object>();     }      // ...more... } 

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:

class SpecialFoo extends Foo {     private void doSomething(Map<String, Object> t) { // <== Changed         // ...     }      public void whatever() {         this.doSomething(this.getThings());         this.doSomething(this.getMoreThings());     } } 

...and changing Foo wouldn't have made SpecialFoo 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 a Map.

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 with SpecialFoo. If Mary had remembered that, then even though I messed up Foo, she would have declared her private method with Map instead of HashMap and my changing Foo'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.

like image 117
T.J. Crowder Avatar answered Oct 10 '22 15:10

T.J. Crowder


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

like image 44
Graphics Noob Avatar answered Oct 10 '22 15:10

Graphics Noob