我所创建的以下地图之间的区别是什么(在另一个问题中,人们似乎可以互换地使用它们,我想知道它们是否/如何不同):
HashMap<String, Object> map = new HashMap<String, Object>();
Map<String, Object> map = new HashMap<String, Object>();
我所创建的以下地图之间的区别是什么(在另一个问题中,人们似乎可以互换地使用它们,我想知道它们是否/如何不同):
HashMap<String, Object> map = new HashMap<String, Object>();
Map<String, Object> map = new HashMap<String, Object>();
当前回答
HashMap<String, Object> map1 = new HashMap<String, Object>();
Map<String, Object> map2 = new HashMap<String, Object>();
首先,Map是一个接口,它有不同的实现,如HashMap, TreeHashMap, LinkedHashMap等。接口的工作方式类似于实现类的超类。因此,根据面向对象的规则,任何实现Map的具体类也是Map。这意味着我们可以将任何HashMap类型变量赋值/放置到Map类型变量,而不需要任何类型的强制转换。
在这种情况下,我们可以将map1分配给map2,而不需要任何强制转换或丢失数据
map2 = map1
其他回答
Map有以下实现:
HashMap Map m = new HashMap(); LinkedHashMap映射m = new LinkedHashMap(); TreeMap Map m = new TreeMap(); WeakHashMap映射m = new WeakHashMap();
假设您已经创建了一个方法(这只是伪代码)。
public void HashMap getMap(){
return map;
}
假设你的项目需求改变了:
该方法应该返回映射内容-需要返回HashMap。 该方法应该返回映射键的插入顺序-需要改变返回类型HashMap到LinkedHashMap。 该方法应该按顺序返回映射键-需要将返回类型LinkedHashMap更改为TreeMap。
如果您的方法返回特定的类,而不是实现Map接口的东西,那么您每次都必须更改getMap()方法的返回类型。
但是如果您使用Java的多态性特性,而不是返回特定的类,而是使用接口Map,它将提高代码的可重用性并减少需求更改的影响。
你创建了相同的地图。
但是当你使用它的时候,你可以弥补这个差异。对于第一种情况,你将能够使用特殊的HashMap方法(但我不记得有什么真正有用的方法),并且你将能够将它作为HashMap参数传递:
public void foo (HashMap<String, Object) { ... }
...
HashMap<String, Object> m1 = ...;
Map<String, Object> m2 = ...;
foo (m1);
foo ((HashMap<String, Object>)m2);
HashMap<String, Object> map1 = new HashMap<String, Object>();
Map<String, Object> map2 = new HashMap<String, Object>();
首先,Map是一个接口,它有不同的实现,如HashMap, TreeHashMap, LinkedHashMap等。接口的工作方式类似于实现类的超类。因此,根据面向对象的规则,任何实现Map的具体类也是Map。这意味着我们可以将任何HashMap类型变量赋值/放置到Map类型变量,而不需要任何类型的强制转换。
在这种情况下,我们可以将map1分配给map2,而不需要任何强制转换或丢失数据
map2 = map1
对象之间没有区别;你有一个HashMap<String,对象>在这两种情况下。你和对象之间的界面是有区别的。在第一种情况下,接口是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->对象的内部映射,它与子类共享(通过访问方法)。假设我一开始是用HashMaps写的因为我认为这是写类时使用的合适结构。
后来,Mary编写代码继承它。她对things和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...
}
后来,我决定,实际上,如果我在Foo中使用TreeMap而不是HashMap会更好。我更新Foo,将HashMap更改为TreeMap。现在,SpecialFoo不再编译了,因为我已经打破了契约:Foo曾经说它提供HashMaps,但现在它提供TreeMaps。所以我们现在必须修复SpecialFoo(这类事情可能会波及整个代码库)。
除非我有一个很好的理由来分享我的实现是使用HashMap(这确实发生了),我应该做的是声明getThings和getMoreThings只是返回Map<String,对象>而不是任何更具体的。事实上,除非有一个很好的理由去做别的事情,即使在Foo中,我也应该将things和更多的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的契约也不会影响她的代码。
有时你不能这样做,有时你必须具体一点。但除非你有理由这么做,否则最好选择最不特定的界面。
HashMap是Map的一个实现,所以它是完全相同的,但有“clone()”方法,因为我在参考指南中看到))