我建立的如下地圖之間有什麼區別(在另外一個問題中,人們彷佛能夠互換使用它們,我想知道它們是否/如何不一樣): this
HashMap<String, Object> map = new HashMap<String, Object>(); Map<String, Object> map = new HashMap<String, Object>();
您建立相同的地圖。 編碼
可是您能夠在使用時彌補差別。 在第一種狀況下,您將可以使用特殊的HashMap方法(但我不記得任何人真的有用),而且您能夠將其做爲HashMap參數傳遞: spa
public void foo (HashMap<String, Object) { ... } ... HashMap<String, Object> m1 = ...; Map<String, Object> m2 = ...; foo (m1); foo ((HashMap<String, Object>)m2);
對象之間沒有區別; 在兩種狀況下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
後來,瑪麗編寫了將其子類化的代碼。 她須要同時處理things
和moreThings
,所以天然而然地將其放在一個通用方法中,而且在定義她的方法時,她使用與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
(而且確實發生了),不然我應該作的就是將getThings
和getMoreThings
聲明爲僅返回Map<String, Object>
而沒有比這更具體的聲明。 實際上,除非有充分的理由作其餘事情,即便在Foo
我也應該將things
和moreThings
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
的合同不會影響她的代碼。
有時候你作不到,有時候你必需要具體。 可是除非有理由,不然請針對最不特定的界面。
在第二個示例中,「 map」引用的類型爲Map
,這是由HashMap
(以及其餘類型的Map
)實現的接口。 這個接口是一個約定,表示對象將鍵映射到值並支持各類操做(例如put
和get
)。 它沒有提到 Map
的實現 (在本例中爲HashMap
)。
一般首選第二種方法,由於您一般不但願使用Map
或經過API定義將特定的Map實現公開給方法。
Map是Interface,而Hashmap是實現該接口的類。
所以,在此實現中,您將建立相同的對象
正如TJ Crowder和Adamski所指出的,一種參考是接口,另外一種是接口的特定實現。 根據Joshua Block的說法,您應該始終嘗試對接口進行編碼,以使您可以更好地處理對基礎實現的更改-即,若是HashMap忽然對於您的解決方案不理想,而且您須要更改Map的實現,那麼您仍然可使用Map接口,並更改實例化類型。