我所创建的以下地图之间的区别是什么(在另一个问题中,人们似乎可以互换地使用它们,我想知道它们是否/如何不同):
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>();
当前回答
Map是静态类型的映射,而HashMap是动态类型的映射。这意味着编译器将把您的map对象视为map类型之一,即使在运行时,它可能指向它的任何子类型。
这种针对接口而不是实现进行编程的实践具有保持灵活性的额外好处:例如,您可以在运行时替换映射的动态类型,只要它是map的子类型(例如LinkedHashMap),并动态地更改映射的行为。
一个好的经验法则是在API级别上尽可能保持抽象:例如,如果您正在编程的方法必须在Map上工作,那么将参数声明为Map而不是更严格的(因为不太抽象)HashMap类型就足够了。这样,API的使用者就可以灵活地决定他们想要传递给方法的Map实现的类型。
其他回答
加上投票最多的答案和上面许多强调“更通用,更好”的答案,我想再挖掘一点。
Map是一个结构契约,而HashMap是一个实现,它提供了自己的方法来处理不同的实际问题:如何计算索引,容量是多少以及如何增加它,如何插入,如何保持索引惟一,等等。
让我们看看源代码:
在Map中,我们有containsKey(对象键)方法:
boolean containsKey(Object key);
JavaDoc:
boolean java.util.Map.containsValue(Object value) Returns true if this map maps one or more keys to the specified value. More formally, returns true if and only if this map contains at least one mapping to a value v such that (value==null ? v==null : value.equals(v)). This operation will probably require time linear in the map size for most implementations of the Map interface. Parameters:value value whose presence in this map is to betested Returns:true if this map maps one or more keys to the specified valueThrows: ClassCastException - if the value is of an inappropriate type for this map (optional) NullPointerException - if the specified value is null and this map does not permit null values (optional)
它需要它的实现来实现它,但“如何”是自由的,只是为了确保它返回正确的结果。
在HashMap:
public boolean containsKey(Object key) {
return getNode(hash(key), key) != null;
}
事实证明,HashMap使用hashcode来测试这个映射是否包含键。所以它有哈希算法的优点。
Map是静态类型的映射,而HashMap是动态类型的映射。这意味着编译器将把您的map对象视为map类型之一,即使在运行时,它可能指向它的任何子类型。
这种针对接口而不是实现进行编程的实践具有保持灵活性的额外好处:例如,您可以在运行时替换映射的动态类型,只要它是map的子类型(例如LinkedHashMap),并动态地更改映射的行为。
一个好的经验法则是在API级别上尽可能保持抽象:例如,如果您正在编程的方法必须在Map上工作,那么将参数声明为Map而不是更严格的(因为不太抽象)HashMap类型就足够了。这样,API的使用者就可以灵活地决定他们想要传递给方法的Map实现的类型。
正如TJ Crowder和Adamski所指出的,一个引用指向一个接口,另一个引用指向接口的特定实现。根据Joshua Block的说法,你应该总是尝试对接口进行编码,以允许你更好地处理底层实现的变化——也就是说,如果HashMap突然不适合你的解决方案,你需要改变映射实现,你仍然可以使用map接口,并改变实例化类型。
Map是接口,Hashmap是实现接口的类。
在这个实现中,你创建了相同的对象
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,它将提高代码的可重用性并减少需求更改的影响。