Java中的HashMap和Map對象之間有什麼區別?

我建立的如下地圖之間有什麼區別(在另外一個問題中,人們彷佛能夠互換使用它們,我想知道它們是否/如何不一樣): this

HashMap<String, Object> map = new HashMap<String, Object>();
Map<String, Object> map = new HashMap<String, Object>();

#1樓

您建立相同的地圖。 編碼

可是您能夠在使用時彌補差別。 在第一種狀況下,您將可以使用特殊的HashMap方法(但我不記得任何人真的有用),而且您能夠將其做爲HashMap參數傳遞: spa

public void foo (HashMap<String, Object) { ... }

...

HashMap<String, Object> m1 = ...;
Map<String, Object> m2 = ...;

foo (m1);
foo ((HashMap<String, Object>)m2);

#2樓

對象之間沒有區別; 在兩種狀況下HashMap<String, Object>您都有HashMap<String, Object> 。 與對象之間的接口有所不一樣。 在第一種狀況下,接口是HashMap<String, Object> ,而在第二種狀況下,接口是Map<String, Object> 。 可是底層對象是相同的。 code

使用Map<String, Object>的優勢在於,您能夠將基礎對象更改成另外一種類型的映射,而不會違反使用該映射的任何代碼的約定。 若是將其聲明爲HashMap<String, Object>HashMap<String, Object>更改基礎實現,則必須更改合同。 對象


示例:假設我編寫了此類: 接口

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...
}

該類有一些string-> object的內部映射,它與子類共享(經過訪問器方法)。 假設我首先使用HashMap編寫它,由於我認爲這是編寫類時要使用的適當結構。 ci

後來,瑪麗編寫了將其子類化的代碼。 她須要同時處理thingsmoreThings ,所以天然而然地將其放在一個通用方法中,而且在定義她的方法時,她使用與getThings / getMoreThings相同的類型: get

class SpecialFoo extends Foo {
    private void doSomething(HashMap<String, Object> t) {
        // ...
    }

    public void whatever() {
        this.doSomething(this.getThings());
        this.doSomething(this.getMoreThings());
    }

    // ...more...
}

稍後,我決定實際上,最好是在Foo使用TreeMap而不是HashMap 。 我更新Foo ,將HashMap更改成TreeMap 。 如今, SpecialFoo再也不編譯,由於我違反了合同: Foo曾經說它提供了HashMap ,可是如今提供了TreeMaps 。 所以,咱們如今必須修復SpecialFoo (這種事情可能會在代碼庫中引發漣漪)。 string

除非我有一個很好的理由要分享個人實現正在使用HashMap (而且確實發生了),不然我應該作的就是將getThingsgetMoreThings聲明爲僅返回Map<String, Object>而沒有比這更具體的聲明。 實際上,除非有充分的理由作其餘事情,即便在Foo我也應該將thingsmoreThings things聲明爲Map ,而不是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...
}

請注意,我如今如何在全部可能的地方使用Map<String, Object> ,僅在建立實際對象時才具體使用。

若是我這樣作了,那麼瑪麗就會作到這一點:

class SpecialFoo extends Foo {
    private void doSomething(Map<String, Object> t) { // <== Changed
        // ...
    }

    public void whatever() {
        this.doSomething(this.getThings());
        this.doSomething(this.getMoreThings());
    }
}

...而且更改Foo不會使SpecialFoo中止編譯。

接口(和基類)使咱們顯示必要的內容,所以能夠靈活地進行更改。 總的來講,咱們但願參考文獻儘量基本。 若是咱們不須要知道它是HashMap ,只需將其稱爲Map

這不是一個盲目的規則,但總的來講, 與最特定的接口編碼相比,對最通用的接口進行編碼將不那麼困難。 若是我還記得這一點,那麼我不會建立一個讓Mary因SpecialFoo失敗而建立的Foo 。 若是Mary記得這一點,那麼即便我搞砸了Foo ,她也會使用Map而不是HashMap聲明她的私有方法,而且我更改Foo的合同不會影響她的代碼。

有時候你作不到,有時候你必需要具體。 可是除非有理由,不然請針對最不特定的界面。


#3樓

在第二個示例中,「 map」引用的類型爲Map ,這是由HashMap (以及其餘類型的Map )實現的接口。 這個接口是一個約定,表示對象將鍵映射到值並支持各類操做(例如putget )。 它沒有提到 Map 的實現 (在本例中爲HashMap )。

一般首選第二種方法,由於您一般不但願使用Map或經過API定義將特定的Map實現公開給方法。


#4樓

Map是Interface,而Hashmap是實現該接口的類。

所以,在此實現中,您將建立相同的對象


#5樓

正如TJ Crowder和Adamski所指出的,一種參考是接口,另外一種是接口的特定實現。 根據Joshua Block的說法,您應該始終嘗試對接口進行編碼,以使您可以更好地處理對基礎實現的更改-即,若是HashMap忽然對於您的解決方案不理想,而且您須要更改Map的實現,那麼您仍然可使用Map接口,並更改實例化類型。

相關文章
相關標籤/搜索