我创建的以下地图之间有什么区别(在另一个问题中,人们似乎可以互换使用它们来回答,我想知道它们是否/如何不同):
HashMap<;字符串,对象>;map=新HashMap<;字符串,对象>;();
地图<;字符串,对象>;map=新HashMap<;字符串,对象>;();
对象之间没有区别;您有一个HashMap<;字符串,对象>在这两种情况下。在对象的界面中存在差异。在第一种情况下,接口是HashMap<;字符串,对象>,而第二个是Map<;字符串,对象>。但底层对象是相同的
使用Map<;字符串,对象>是指您可以将底层对象更改为不同类型的映射,而不必破坏与使用它的任何代码的约定。如果将其声明为HashMap<;字符串,对象>,如果要更改基础实现,则必须更改合同
示例:假设我编写了这个类:
类Foo{
私有HashMap<;字符串、对象>;事物;
私有哈希映射<;字符串,对象>;更多内容;
受保护的HashMap<;字符串、对象>;getThings(){
归还这个东西;
}
受保护的HashMap<;字符串、对象>;getMoreThings(){
归还这个。更多的东西;
}
公共食物({
this.things=newhashmap<;String,Object>;();
this.moreights=newhashmap<;String,Object>;();
}
//……更多。。。
}
该类有两个字符串->对象的内部映射,它(通过访问器方法)与子类共享这些映射。假设我首先使用HashMaps编写它,因为我认为这是编写类时使用的适当结构
后来,Mary编写了将其子类化的代码。她需要处理事物和更多事物,因此她自然地将其放在一个通用方法中,并且在定义她的方法时,她使用了我在获取事物/获取更多事物上使用的相同类型:
类SpecialFoo扩展了Foo{
私有void doSomething(HashMap<;String,Object>;t){
// ...
}
公共空间{
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
//……更多。。。
}
后来,我决定实际上,如果我在Foo中使用TreeMap而不是HashMap,效果会更好。我更新了Foo,将HashMap更改为TreeMap。现在,SpecialFoo不再编译了,因为我已经破坏了合约:Foo以前说它提供了HashMaps,但现在它提供了TreeMaps。因此,我们现在必须修复SpecialFoo(这种事情可能会在代码库中产生涟漪)
除非我有很好的理由分享我的实现使用了一个HashMap(这确实发生了),否则我应该做的是将getThings和getMoreThings声明为只返回Map<;字符串,对象>没有比这更具体的内容。事实上,除非有充分的理由去做其他事情,即使是在Foo中,我也应该将事物和更多事物声明为Map,而不是HashMap/TreeMap:
类Foo{
私有映射<;字符串,对象>;事物;//<;==已更改
私有映射<;字符串,对象>;moreThings;//<;==已更改
受保护的映射<;字符串,对象>;getThings(){/<;==已更改
归还这个东西;
}
受保护的映射<;字符串,对象>;getMoreThings(){/<;==已更改
归还这个。更多的东西;
}
公共食物({
this.things=newhashmap<;String,Object>;();
this.moreights=newhashmap<;String,Object>;();
}
//……更多。。。
}
注意我现在是如何使用Map<;字符串,对象>我能做到的任何地方,只有在我创建实际对象时才是特定的
如果我那样做了,玛丽就会这样做:
类SpecialFoo扩展了Foo{
私有void doSomething(映射<;字符串,对象>;t){/<;==已更改
// ...
}
公共空间{
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
}
…更改Foo不会使SpecialFoo停止编译
接口(和基类)允许我们只显示必要的,,保持我们的灵活性,以便进行适当的更改。一般来说,我们希望我们的参考资料尽可能基本。如果我们不需要知道它是一个HashMap,那就称它为Map
这不是一条盲目的规则,但一般来说,编码到最通用的接口要比编码到更具体的接口更不脆弱。如果我记得的话,我就不会创建一个Foo,用SpecialFoo设置Mary失败。如果玛丽记得,那么即使我把Foo搞砸了,她也会用Map而不是HashMap声明她的私人方法,而我更改Foo的合同也不会影响她的代码
有时候你做不到,有时候你必须明确。但是,除非你有理由这样做,否则就应该选择最不具体的接口