java hashmap 对象_Java中的HashMap和Map对象之间有什么区别?

我创建的以下地图之间有什么区别(在另一个问题中,人们似乎可以互换使用它们,我想知道它们是否/如何不同):

HashMap map = new HashMap();

Map map = new HashMap();

#1楼

您创建相同的地图。

但是您可以在使用时弥补差异。 在第一种情况下,您将能够使用特殊的HashMap方法(但我不记得任何人真的有用),并且您可以将其作为HashMap参数传递:

public void foo (HashMap

...

HashMap m1 = ...;

Map m2 = ...;

foo (m1);

foo ((HashMap)m2);

#2楼

对象之间没有区别; 在两种情况下HashMap您都有HashMap 。 与对象之间的接口有所不同。 在第一种情况下,接口是HashMap ,而在第二种情况下,接口是Map 。 但是底层对象是相同的。

使用Map的优点在于,您可以将基础对象更改为另一种类型的映射,而不会违反使用该映射的任何代码的约定。 如果将其声明为HashMap , HashMap更改基础实现,则必须更改合同。

示例:假设我编写了此类:

class Foo {

private HashMap things;

private HashMap moreThings;

protected HashMap getThings() {

return this.things;

}

protected HashMap getMoreThings() {

return this.moreThings;

}

public Foo() {

this.things = new HashMap();

this.moreThings = new HashMap();

}

// ...more...

}

该类有一些string-> object的内部映射,它与子类共享(通过访问器方法)。 假设我首先使用HashMap编写它,因为我认为这是编写类时要使用的适当结构。

后来,玛丽编写了将其子类化的代码。 她需要同时处理things和moreThings ,因此自然而然地将其放在一个通用方法中,并且在定义她的方法时,她使用与getThings / getMoreThings相同的类型:

class SpecialFoo extends Foo {

private void doSomething(HashMap t) {

// ...

}

public void whatever() {

this.doSomething(this.getThings());

this.doSomething(this.getMoreThings());

}

// ...more...

}

稍后,我决定实际上,最好是在Foo使用TreeMap而不是HashMap 。 我更新Foo ,将HashMap更改为TreeMap 。 现在, SpecialFoo不再编译,因为我违反了合同: Foo曾经说它提供了HashMap ,但是现在提供了TreeMaps 。 因此,我们现在必须修复SpecialFoo (这种事情可能会在代码库中引起涟漪)。

除非我有一个很好的理由要分享我的实现正在使用HashMap (并且确实发生了),否则我应该做的就是将getThings和getMoreThings声明为仅返回Map而没有比这更具体的声明。 实际上,除非有充分的理由做其他事情,即使在Foo我也应该将things和moreThings things声明为Map ,而不是HashMap / TreeMap :

class Foo {

private Map things; // <== Changed

private Map moreThings; // <== Changed

protected Map getThings() { // <== Changed

return this.things;

}

protected Map getMoreThings() { // <== Changed

return this.moreThings;

}

public Foo() {

this.things = new HashMap();

this.moreThings = new HashMap();

}

// ...more...

}

请注意,我现在如何在所有可能的地方使用Map ,仅在创建实际对象时才具体使用。

如果我这样做了,那么玛丽就会做到这一点:

class SpecialFoo extends Foo {

private void doSomething(Map 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的合同不会影响她的代码。

有时候你做不到,有时候你必须要具体。 但是除非有理由,否则请针对最不特定的界面。

#3楼

在第二个示例中,“ map”引用的类型为Map ,这是由HashMap (以及其他类型的Map )实现的接口。 这个接口是一个约定,表示对象将键映射到值并支持各种操作(例如put和get )。 它没有提到 Map 的实现 (在本例中为HashMap )。

通常首选第二种方法,因为您通常不希望使用Map或通过API定义将特定的Map实现公开给方法。

#4楼

Map是Interface,而Hashmap是实现该接口的类。

因此,在此实现中,您将创建相同的对象

#5楼

正如TJ Crowder和Adamski所指出的,一种参考是接口,另一种是接口的特定实现。 根据Joshua Block的说法,您应该始终尝试对接口进行编码,以使您能够更好地处理对基础实现的更改-即,如果HashMap突然对于您的解决方案不理想,并且您需要更改Map的实现,那么您仍然可以使用Map接口,并更改实例化类型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值