Java中的HashMap和Map对象有什么区别?

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

HashMap<String, Object> map = new HashMap<String, Object>();
Map<String, Object> map = new HashMap<String, Object>();

对象之间没有区别; 在这两种情况下你都有一个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编写它以开始,因为我认为这是编写该类时适用的结构。

之后,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曾经说它提供了HashMap ,但现在它提供了TreeMaps 。 所以我们现在必须修复SpecialFoo (这种事情可能会影响代码库)。

除非我有一个很好的理由来分享我的实现使用HashMap (并且确实发生了),否则我应该做的是将getThingsgetMoreThings声明为仅返回Map<String, Object>而不getThings getMoreThings 。 事实上,除了一个很好的理由去做别的事情,即使在Foo我也应该把thingsmoreThings 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

这不是盲目的规则,但总的来说,编码到最普通的接口将比编码更具体的更脆弱。 如果我记得的话,我不会创建一个Foo ,因为SpecialFoo失败而让玛丽SpecialFoo 。 如果玛丽记得那个,那么即使我搞砸了Foo ,她也会用Map而不是HashMap声明她的私有方法,而且我改变Foo的合同不会影响她的代码。

有时你不能那样做,有时你必须具体。 但除非你有一个理由,否则就会碰到最不具体的界面。


Map是HashMap实现的接口。 不同的是,在第二个实现中,对HashMap的引用只允许使用Map接口中定义的函数,而第一个将允许使用HashMap中的任何公共函数(其中包括Map接口)。

如果你阅读Sun的界面教程,它可能会更有意义


我只是将它作为对已接受答案的评论,但它太时髦了(我讨厌没有换行符)

啊,所以区别在于一般情况下,Map有一些与之相关的方法。 但有不同的方式或创建一个地图,如HashMap,这些不同的方式提供了并非所有地图都有的独特方法。

确切地说 - 你总是希望使用最通用的界面,你可能可以。 考虑ArrayList vs LinkedList。 你如何使用它们有很大的不同,但如果你使用“列表”,你可以很容易地在它们之间切换。

实际上,您可以用更动态的语句替换初始化程序的右侧。 如何这样的事情:

List collection;
if(keepSorted)
    collection=new LinkedList();
else
    collection=new ArrayList();

这样,如果要使用插入排序来填充集合,则可以使用链接列表(插入到数组列表中的排序是犯罪行为。)但是,如果您不需要保留排序并且只是追加,您使用ArrayList(对其他操作更高效)。

这是一个很大的延伸,因为集合不是最好的例子,但是在OO设计中,最重要的概念之一是使用界面外观来访问具有完全相同代码的不同对象。

编辑回应评论:

至于下面的地图注释,Yes使用“Map”接口将您限制为只有这些方法,除非您将集合从Map转换回HashMap(完全击败了目的)。

通常你要做的就是创建一个对象,并使用它的特定类型(HashMap),在某种“创建”或“初始化”方法中填充它,但该方法将返回一个不需要的“映射”作为一个HashMap操纵了更多。

如果你不得不顺便施放,你可能使用了错误的界面,或者你的代码结构不够好。 请注意,将代码的一部分视为“HashMap”而另一部分将其视为“Map”是可以接受的,但这应该“向下”流动。 所以你永远不会铸造。

还要注意接口指示的角色的半整齐方面。 LinkedList是一个很好的堆栈或队列,ArrayList是一个很好的堆栈,但是一个可怕的队列(再次,删除会导致整个列表的移动),所以LinkedList实现了Queue接口,而ArrayList则没有。

链接地址: http://www.djcxy.com/p/91913.html

上一篇: What is the difference between the HashMap and Map objects in Java?

下一篇: How to do associative array/hashing in JavaScript