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.

Answer from T.J. Crowder on Stack Overflow
🌐
Oracle
docs.oracle.com › javase › 8 › docs › api › java › util › Map.html
Map (Java Platform SE 8 )
July 21, 2026 - The Map interface provides three collection views, which allow a map's contents to be viewed as a set of keys, collection of values, or set of key-value mappings. The order of a map is defined as the order in which the iterators on the map's collection views return their elements.
🌐
W3Schools
w3schools.com › java › java_map.asp
Java Map
The Map interface is a part of the Java Collections Framework and is used to store key-value pairs.
🌐
Redisson
redisson.pro › glossary › java-map.html
What is a Java map? | Redisson
Java maps are an implementation of the map abstract data type for the Java programming language. Maps link keys with values: given a key, the map will return the associated value. Each key is unique, but the associated values may not be.
🌐
GeeksforGeeks
geeksforgeeks.org › java › map-interface-in-java
Map Interface in Java - GeeksforGeeks
In Java, the Map Interface is part of the java.util package and represents a collection of key-value pairs, where Keys should be unique, but values can be duplicated.
Published: August 31, 2026
🌐
Medium
medium.com › @pratik.941 › unlocking-the-power-of-the-map-interface-in-java-6e1dcfd93b06
Unlocking the Power of the Map Interface in Java | by Pratik T | Medium
June 17, 2024 - The `Map` interface is a key part of the Java Collections Framework and represents a collection of key-value pairs. Unlike other collections that only store elements, a `Map` stores mappings from unique keys to values, enabling efficient data ...
🌐
YouTube
youtube.com › watch
Map and HashMap in Java - Full Tutorial - YouTube
Complete Java course: https://codingwithjohn.thinkific.com/courses/java-for-beginnersMaps and HashMaps in Java can be so confusing when you're first starting
Published: June 14, 2021
Top answer
1 of 13
577

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.

2 of 13
65

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

Find elsewhere
🌐
Java
download.java.net › java › early_access › panama › docs › api › java.base › java › util › HashMap.html
HashMap (Java SE 19 & JDK 19 [build 1])
Higher values decrease the space overhead but increase the lookup cost (reflected in most of the operations of the HashMap class, including get and put). The expected number of entries in the map and its load factor should be taken into account when setting its initial capacity, so as to minimize the number of rehash operations.
🌐
Stackify
stackify.com › an-introduction-to-java-map-what-it-is-and-how-it-works
An Introduction to Java Map: What It Is and How It Works - Stackify
November 26, 2024 - Java Maps are powerful tools for all developers, using key-value pairs to simplify organizing, storing, searching, and retrieving data.
🌐
Oracle
docs.oracle.com › en › java › javase › 11 › docs › api › java.base › java › util › Map.html
Map (Java SE 11 & JDK 11 )
January 20, 2026 - It is convenient to create the map entries using the Map.entry() method. For example, import static java.util.Map.entry; Map<Integer,String> map = Map.ofEntries( entry(1, "a"), entry(2, "b"), entry(3, "c"), ...
🌐
Codecademy
codecademy.com › docs › java › map
Java | Map | Codecademy
April 30, 2022 - The Map interface is found in java.util and it allows collections to store items as key-value pairs. It is implemented in the HashMap and TreeMap classes. A Map allows its contents to be accessed as a set of keys, a set of values, or a set of ...
🌐
CodeSignal
codesignal.com › learn › courses › mastering-complex-data-structures-in-java › lessons › exploring-maps-and-hashmap-in-java
Exploring Maps and HashMap in Java
Today, we will delve deeply into Java Maps. Much like a bookshelf, Maps allow you to quickly select the book (value) you desire by reading its label (key). They are vital in Java for quickly accessing values using keys and for efficiently inserting and deleting keys.
🌐
Medium
medium.com › @himani.prasad016 › map-in-java-fdcbdbf5c9ce
Map in Java. The Map interface in Java is a powerful… | by Himani Prasad | Medium
June 11, 2023 - The Map interface is part of the Java Collections Framework and is defined in the java.util package. It represents a mapping between unique keys and their corresponding values.
🌐
Medium
medium.com › @AlexanderObregon › javas-stream-map-method-explained-df0d0d461d39
Java’s Stream.map() Method Explained | Medium
August 27, 2024 - The map() method is at the heart of data transformation in Java's Stream API. Whether you are dealing with simple data types like strings and integers or complex objects, map() allows you to transform and manipulate data in a clean, functional style.
🌐
W3Schools
w3schools.com › java › java_hashmap.asp
Java HashMap
It is part of the java.util package and implements the Map interface.
🌐
Android Developers
developer.android.com › api reference › map
Map | API reference | Android Developers
August 3, 2026 - Skip to main content · English · Deutsch · Español – América Latina · Français · Indonesia · Polski · Português – Brasil · Tiếng Việt · 中文 – 简体
🌐
Baeldung
baeldung.com › home › java › java collections › java map › a guide to java hashmap
A Guide to Java HashMap | Baeldung
January 15, 2025 - A class very similar to HashMap is Hashtable. Please refer to a couple of our other articles to learn more about the java.util.Hashtable class itself and the differences between HashMap and Hashtable. Let’s first look at what it means that HashMap is a map.
Top answer
1 of 2
9

For Java 9 and beyond, you can make use of Map#of, as well as Map#ofEntries with Map#entry:

Map<String, String> example = Map.ofEntries(
    Map.entry("1", "one"),
    Map.entry("2", "two"),
    Map.entry("3", "three"),
    //...
);

For shorter literals (10 or less entries), you can use Map#of directly (albeit with a slightly confusing syntax of Key1, Value1, Key2, Value2, ...):

Map<String, String> example = Map.of("1", "one", "2", "two");

Prior to Java 9, this would typically only be needed for initializing constant Map objects, for which a static initializer block is also useful:

private static final Map<String, String> MY_CONSTANT;

static {
    Map<String, String> setup = new HashMap<>();
    setup.put("1", "one");
    setup.put("2", "two");
    setup.put("3", "three");
    MY_CONSTANT = Collections.unmodifiableMap(setup);
}

This will allow you to create a constant Map while allowing you to modify the map before it is set.

As pointed out by @Pshemo, there are numerous reasons to avoid double-brace initialization, however the notable exception to the "rule" is typically in constants much like the above example (as numerous anonymous classes would not be made). However, it is still possible to work around the need for double-brace initialization even in this case, so it is overall best to avoid if possible. The only case I can think of this not being possible is within the context of a constant within an enum class, where the double-brace init may truly be the only true way to make this work.

2 of 2
2

Firstly, you shouldn't use Hashtable class - it's legacy. If you need a general purpose implementation of the Map interface, use HashMap instead.

In case when you need to initialize a general purpose Map with a few entries, you can use one of the overloaded versions of Map.of() method which is available starting with Java 9. It allows providing up to 10 key-value pairs, if you need more you can use Map.ofEntries(), which takes a varargs of map entries. You can create a map entry using another Java 9 method Map.entry().

Example:

public static final Map<String, Integer> numbers = 
    Map.of("one", 1, "two", 2, "three", 3);

Note these maps are

1. Immutable, therefore it would be the right choice only if the data never change (or might change rarely, i.e. in case of very frequent reads and infrequent writes, and every write would require re-initializing the map).

2 So-called unmodifiable maps like MapN (which is an internal implementation used by Map.ofEntries() intended to store an arbitrary number of key-value pairs) are optimized in terms of Memory consumption, their underlying array occupies exactly as match space as match there are key-value pairs and no more, and retrieving a value from an unmodifiable map using get() might even perform slightly better (see the quote below) in comparison to a HashMap.

For more information you can refer to official documentation - Creating Immutable Lists, Sets, and Maps:

Use Cases

The common use case for the immutable methods is a collection that is initialized from known values, and that never changes. Also consider using these methods if your data changes infrequently.

For optimal performance, the immutable collections store a data set that never changes. However, you may be able to take advantage of the performance and space-saving benefits even if your data is subject to change. These collections may provide better performance than the mutable collections, even if your data changes occasionally.

If you have a large number of values, you may consider storing them in a HashMap. If you are constantly adding and removing entries, then this is a good choice. But, if you have a set of values that never change, or rarely change, and you read from that set a lot, then the immutable Map is a more efficient choice. If the data set is read frequently, and the values change only rarely, then you may find that the overall speed is faster, even when you include the performance impact of destroying and rebuilding an immutable Map when a value changes.

Also note that depending on the type of keys and the actual data (specifically on the number of collisions), an unmodifiable map might perform worse than a HashMap because contrary to HashMap unmodifiable map is incapable to store and reuse hashes of the keys and hence might perform more comparisons of keys using equals method. And in case of large number of collisions, unmodifiable map has no means to mitigate performance degradation, unlike HashMap which since would try to arrange nodes into a tree when the number of nodes in a bucket exceeds certain threshold.

Spiking of other alternatives doubly-brace initialization, which creates an instance of anonymous inner class, is indisputably a discouraged practice.

Static and instance initializer blocks have no downsides from the technical point of view, they allow you to keep the variables final if you need that. But some might argue that from the perspective of clean coding, initializer blocks are not very great.

Another possibility you might consider is to initialize a map inline using Stream API (for instance, when map-data can be expressed as a sequence that is easy to generate).

🌐
Exia
exia.dev › java › Basic › 11-map
Map In Java - Java Collections - Jun's Learning
May 13, 2023 - Map is a key-value data structure in Java and other languages, it uses an array to save the key-value data, by hashing the key to an integer, then map to array index.
🌐
Google
docs.cloud.google.com › load balancing › url map size and quota units
URL map size and quota units | Cloud Load Balancing | Google Cloud Documentation
August 26, 2026 - The output includes a read-only status.quotaUsage object showing the total number of units calculated for the URL map, as well as the number of forwarding rules using it. For more information, see Quotas and limits. Quotas and limits. ... Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.