物体之间没有区别;你有一个HashMap<String, Object>
在这两种情况下。存在差异界面你必须到对象。第一种情况,接口是HashMap<String, Object>
,而在第二个中它是Map<String, Object>
。但底层对象是相同的。
使用的优点Map<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
首先是因为我认为这是编写类时使用的合适结构。
后来,玛丽编写了子类化它的代码。她有一些事需要和这两个人一起做things
and moreThings
,所以她很自然地把它放在一个通用方法中,并且她使用了我使用的相同类型getThings
/getMoreThings
在定义她的方法时:
class SpecialFoo extends Foo {
private void doSomething(HashMap<String, Object> t) {
// ...
}
public void whatever() {
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
// ...more...
}
后来,我决定实际上,如果我使用的话会更好TreeMap
代替HashMap
in Foo
。我更新Foo
,改变HashMap
to TreeMap
. Now, SpecialFoo
不再编译,因为我违反了合同:Foo
过去常说它提供了HashMap
s,但现在它提供TreeMaps
反而。所以我们必须修复SpecialFoo
现在(这种事情可能会影响代码库)。
除非我有一个很好的理由来分享我的实现是使用HashMap
(这确实发生了),我应该做的是声明getThings
and getMoreThings
就像刚回来一样Map<String, Object>
没有比这更具体的了。事实上,除非有充分的理由去做其他事情,即使在内部Foo
我也许应该声明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...
}
请注意我现在如何使用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
.
这并不是一个盲目的规则,但总的来说,编码为最通用的接口与编写更具体的内容相比,它不会那么脆弱。如果我记得这一点,我就不会创建一个Foo
这让玛丽陷入了失败SpecialFoo
. If Mary记得那件事,尽管我搞砸了Foo
,她会声明她的私有方法Map
代替HashMap
和我的改变Foo
的合同不会影响她的代码。
有时你不能这样做,有时你必须具体。但除非你有理由这样做,否则最好选择最不具体的界面。