What is the difference between the following maps I create (in another question, people answered using them seemingly interchangeably and I'm wondering if/how they are different):
我创作的下面的地图有什么不同(在另一个问题中,人们似乎可以交换地使用它们来回答,我想知道它们是否有什么不同):
HashMap<String, Object> map = new HashMap<String, Object>();Map<String, Object> map = new HashMap<String, Object>();
13 个解决方案
#1
347
There is no difference between the objects; you have a HashMap<String, Object>
in both cases. There is a difference in the interface you have to the object. In the first case, the interface is HashMap<String, Object>
, whereas in the second it's Map<String, Object>
. But the underlying object is the same.
物体之间没有区别;两种情况下都有HashMap
The advantage to using Map<String, Object>
is that you can change the underlying object to be a different kind of map without breaking your contract with any code that's using it. If you declare it as HashMap<String, Object>
, you have to change your contract if you want to change the underlying implementation.
使用Map
Example: Let's say I write this class:
比方说我写了这门课:
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...}
The class has a couple of internal maps of string->object which it shares (via accessor methods) with subclasses. Let's say I write it with HashMap
s to start with because I think that's the appropriate structure to use when writing the class.
该类有两个字符串->对象的内部映射,它与子类共享(通过accessor方法)。假设我用hashmap开始,因为我认为这是在编写类时使用的合适结构。
Later, Mary writes code subclassing it. She has something she needs to do with both things
and moreThings
, so naturally she puts that in a common method, and she uses the same type I used on getThings
/getMoreThings
when defining her method:
稍后,Mary编写代码子类化。她有一些她需要做的事情和更多的事情,所以自然她把它放在一个普通的方法中,她使用了我在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...}
Later, I decide that actually, it's better if I use TreeMap
instead of HashMap
in Foo
. I update Foo
, changing HashMap
to TreeMap
. Now, SpecialFoo
doesn't compile anymore, because I've broken the contract: Foo
used to say it provided HashMap
s, but now it's providing TreeMaps
instead. So we have to fix SpecialFoo
now (and this kind of thing can ripple through a codebase).
稍后,我决定实际上,如果我在Foo中使用TreeMap而不是HashMap会更好。我更新Foo,将HashMap更改为TreeMap。现在,SpecialFoo不再编译了,因为我破坏了约定:Foo过去说它提供了HashMaps,但是现在它提供了TreeMaps。所以我们现在必须修复SpecialFoo(这类东西可以通过代码基传播)。
Unless I had a really good reason for sharing that my implementation was using a HashMap
(and that does happen), what I should have done was declare getThings
and getMoreThings
as just returning Map<String, Object>
without being any more specific than that. In fact, barring a good reason to do something else, even within Foo
I should probably declare things
and moreThings
as Map
, not HashMap
/TreeMap
:
除非我有一个很好的理由来分享我的实现使用了HashMap(这确实发生了),否则我应该做的就是声明getThings和getMoreThings作为返回Map
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...}
Note how I'm now using Map<String, Object>
everywhere I can, only being specific when I create the actual objects.
请注意,我现在是如何使用Map
If I had done that, then Mary would have done this:
如果我那样做,玛丽也会这样做:
class SpecialFoo extends Foo { private void doSomething(Map<String, Object> t) { // <== Changed // ... } public void whatever() { this.doSomething(this.getThings()); this.doSomething(this.getMoreThings()); }}
...and changing Foo
wouldn't have made SpecialFoo
stop compiling.
…改变Foo不会让SpecialFoo停止编译。
Interfaces (and base classes) let us reveal only as much as is necessary, keeping our flexibility under the covers to make changes as appropriate. In general, we want to have our references be as basic as possible. If we don't need to know it's a HashMap
, just call it a Map
.
接口(和基类)只允许我们尽可能多地显示所需的内容,保持我们的灵活性,以便进行适当的更改。一般来说,我们希望我们的引用尽可能地基本。如果我们不需要知道它是一个HashMap,就称它为Map。
This isn't a blind rule, but in general, coding to the most general interface is going to be less brittle than coding to something more specific. If I'd remembered that, I wouldn't have created a Foo
that set Mary up for failure with SpecialFoo
. If Mary had remembered that, then even though I messed up Foo
, she would have declared her private method with Map
instead of HashMap
and my changing Foo
's contract wouldn't have impacted her code.
这并不是一个盲目的规则,但一般来说,对最通用的接口进行编码比对更具体的东西进行编码要容易一些。如果我记得的话,我就不会创建一个Foo来设置Mary为SpecialFoo的失败。如果Mary记得,那么即使我把Foo搞砸了,她也会用Map而不是HashMap来声明她的私有方法,而我修改的Foo的契约也不会影响她的代码。
Sometimes you can't do that, sometimes you have to be specific. But unless you have a reason to be, err toward the least-specific interface.
有时候你做不到,有时候你必须具体。但是,除非你有理由这样做,否则最好选择最不特定的界面。
#2
52
Map is an interface that HashMap implements. The difference is that in the second implementation your reference to the HashMap will only allow the use of functions defined in the Map interface, while the first will allow the use of any public functions in HashMap (which includes the Map interface).
Map是HashMap实现的接口。不同的是,在第二个实现中,您对HashMap的引用只允许使用在Map接口中定义的函数,而第一个实现将允许使用HashMap(包括Map接口)中的任何公共函数。
It will probably make more sense if you read Sun's interface tutorial
如果您阅读Sun的界面教程,可能会更有意义。
#3
17
I was just going to do this as a comment on the accepted answer but it got too funky (I hate not having line breaks)
我只是想评论一下大家都接受的答案但是太奇怪了(我讨厌没有换行)
ah, so the difference is that in general, Map has certain methods associated with it. but there are different ways or creating a map, such as a HashMap, and these different ways provide unique methods that not all maps have.
啊,所以区别在于,总的来说,Map有一些与之相关的方法。但是有不同的方法或创建映射,比如HashMap,这些不同的方法提供了独特的方法,而不是所有的映射都有。
Exactly--and you always want to use the most general interface you possibly can. Consider ArrayList vs LinkedList. Huge difference in how you use them, but if you use "List" you can switch between them readily.
确切地说,你总是想用最通用的接口。考虑ArrayList vs LinkedList。你使用它们的方式有很大的不同,但是如果你使用“列表”,你可以很容易地在它们之间切换。
In fact, you can replace the right-hand side of the initializer with a more dynamic statement. how about something like this:
实际上,您可以用更动态的语句替换初始化器的右边。像这样的东西怎么样:
List collection;if(keepSorted) collection=new LinkedList();else collection=new ArrayList();
This way if you are going to fill in the collection with an insertion sort, you would use a linked list (an insertion sort into an array list is criminal.) But if you don't need to keep it sorted and are just appending, you use an ArrayList (More efficient for other operations).
这样,如果您要用插入排序填充集合,您将使用一个链表(数组列表中的插入排序是犯罪的)。但是,如果您不需要对它进行排序和添加,您可以使用ArrayList(其他操作更有效)。
This is a pretty big stretch here because collections aren't the best example, but in OO design one of the most important concepts is using the interface facade to access different objects with the exact same code.
这是一个很大的扩展,因为集合不是最好的例子,但是在OO设计中最重要的概念之一是使用接口facade来访问具有完全相同代码的不同对象。
Edit responding to comment:
编辑回复评论:
As for your map comment below, Yes using the "Map" interface restricts you to only those methods unless you cast the collection back from Map to HashMap (which COMPLETELY defeats the purpose).
对于下面的map注释,如果使用“map”接口,那么只能使用这些方法,除非将集合从map转换回HashMap(这完全违背了目的)。
Often what you will do is create an object and fill it in using it's specific type (HashMap), in some kind of "create" or "initialize" method, but that method will return a "Map" that doesn't need to be manipulated as a HashMap any more.
通常,您要做的是创建一个对象并使用它的特定类型(HashMap)填充它,使用某种“create”或“initialize”方法,但是该方法将返回一个“Map”,不再需要作为HashMap来操作。
If you ever have to cast by the way, you are probably using the wrong interface or your code isn't structured well enough. Note that it is acceptable to have one section of your code treat it as a "HashMap" while the other treats it as a "Map", but this should flow "down". so that you are never casting.
如果您需要强制转换,您可能使用了错误的接口,或者您的代码结构不够好。请注意,您的代码中有一部分将其视为“HashMap”,而另一部分将其视为“Map”,这是可以接受的,但这应该是“向下”的。这样你就不会选角了。
Also notice the semi-neat aspect of roles indicated by interfaces. A LinkedList makes a good stack or queue, an ArrayList makes a good stack but a horrific queue (again, a remove would cause a shift of the entire list) so LinkedList implements the Queue interface, ArrayList does not.
还要注意接口指示的角色的半整洁方面。一个LinkedList创建了一个很好的堆栈或队列,一个ArrayList创建了一个很好的堆栈,但是一个很可怕的队列(同样,删除会导致整个列表的移位),所以LinkedList实现了队列接口,而ArrayList则没有。
#4
16
Map having following implementations,
地图在实现后,
-
HashMap
Map m = new HashMap();
HashMap m = new HashMap();
-
LinkedHashMap
Map m = new LinkedHashMap();
LinkedHashMap m =新的LinkedHashMap();
-
Tree Map
Map m = new TreeMap();
树形图m = new TreeMap();
-
WeakHashMap
Map m = new WeakHashMap();
WeakHashMap m = new WeakHashMap();
Suppose you have created one method (It's just spudo code).
假设您已经创建了一个方法(它只是spudo代码)。
public void HashMap getMap(){ return map;}
Suppose you project requirement are changing each time as follows,
假设您的项目需求每次都在变化,如下所示,
- Method should return map contents - Need to return
HashMap
. - 方法应该返回映射内容——需要返回HashMap。
- Method should return map key's in insertion order - Need to change return type
HashMap
toLinkedHashMap
. - 方法应该按插入顺序返回映射键——需要将返回类型HashMap更改为LinkedHashMap。
- Method should return map key's in sorted order - Need to change return type
LinkedHashMap
toTreeMap
. - 方法应该以排序的顺序返回映射键——需要将返回类型LinkedHashMap更改为TreeMap。
If your method returning Specific classes instead of Map
interface you have to change return type of getMap()
method each time.
如果方法返回特定的类而不是映射接口,那么每次都必须更改getMap()方法的返回类型。
But, If you use polymorphism feature of java, Instead of returning specific class used interface Map
, It leads code reusability and less impact if any requirement change.
但是,如果您使用java的多态性特性,而不是返回特定的类used interface Map,它将导致代码的可重用性,并且在任何需求更改时影响更小。
#5
12
As noted by TJ Crowder and Adamski, one reference is to an interface, the other to a specific implementation of the interface. According to Joshua Block, you should always attempt to code to interfaces, to allow you to better handle changes to underlying implementation - i.e. if HashMap suddenly was not ideal for your solution and you needed to change the map implementation, you could still use the Map interface, and change the instantiation type.
正如TJ Crowder和Adamski所指出的,一个是对接口的引用,另一个是对接口的特定实现的引用。约书亚说,你应该尝试代码界面,让你更好地处理更改底层实现,即如果HashMap突然没有适合您的解决方案,您需要改变地图的实现,您仍然可以使用地图界面,改变实例化类型。
#6
8
In your second example the "map" reference is of type Map
, which is an interface implemented by HashMap
(and other types of Map
). This interface is a contract saying that the object maps keys to values and supports various operations (e.g. put
, get
). It says nothing about the implementation of the Map
(in this case a HashMap
).
在第二个示例中,“map”引用的类型是map,它是HashMap(和其他类型的map)实现的接口。该接口是一个约定,表示对象将键映射到值并支持各种操作(例如put、get)。它没有说明映射的实现(在本例中是HashMap)。
The second approach is generally preferred as you typically wouldn't want to expose the specific map implementation to methods using the Map
or via an API definition.
第二种方法通常是首选的,因为您通常不想使用映射或API定义来公开特定的映射实现。
#7
8
Map is the static type of map, while HashMap is the dynamic type of map. This means that the compiler will treat your map object as being one of type Map, even though at runtime, it may point to any subtype of it.
Map是Map的静态类型,HashMap是Map的动态类型。这意味着编译器将把映射对象视为类型映射,即使在运行时,它可能指向它的任何子类型。
This practice of programming against interfaces instead of implementations has the added benefit of remaining flexible: You can for instance replace the dynamic type of map at runtime, as long as it is a subtype of Map (e.g. LinkedHashMap), and change the map's behavior on the fly.
这种针对接口而不是实现编程的实践还有一个额外的好处:例如,您可以在运行时替换动态映射类型,只要它是映射的子类型(例如LinkedHashMap),并动态地更改映射的行为。
A good rule of thumb is to remain as abstract as possible on the API level: If for instance a method you are programming must work on maps, then it's sufficient to declare a parameter as Map instead of the stricter (because less abstract) HashMap type. That way, the consumer of your API can be flexible about what kind of Map implementation they want to pass to your method.
一个很好的经验法则是在API级别上尽可能保持抽象:如果您正在编程的方法必须处理映射,那么将参数声明为映射就足够了,而不是更严格的HashMap类型(因为不太抽象)。这样,您的API的使用者可以灵活地了解他们想要传递给您的方法的地图实现类型。
#8
3
You create the same maps.
创建相同的映射。
But you can fill the difference when you will use it. With first case you'll be able to use special HashMap methods (but I don't remember anyone realy useful), and you'll be able to pass it as a HashMap parameter:
但是您可以在使用它的时候补上差额。对于第一种情况,您可以使用特殊的HashMap方法(但我不记得有什么有用的方法),并且可以将其作为HashMap参数传递:
public void foo (HashMap<String, Object) { ... }...HashMap<String, Object> m1 = ...;Map<String, Object> m2 = ...;foo (m1);foo ((HashMap<String, Object>)m2);
#9
2
Adding to the top voted answer and many ones above stressing the "more generic, better", I would like to dig a little bit more.
在上面的投票答案和许多强调“更一般,更好”的答案中,我想再深入一点。
Map
is the structure contract while HashMap
is an implementation providing its own methods to deal with different real problems: how to calculate index, what is the capacity and how to increment it, how to insert, how to keep the index unique, etc.
Map是结构契约,HashMap是实现,提供了自己的方法来处理不同的实际问题:如何计算索引、容量是什么、如何增加索引、如何插入、如何保持索引惟一等等。
Let's look into the source code:
让我们看看源代码:
In Map
we have the method of containsKey(Object key)
:
在Map中我们有containsKey(Object key)方法:
boolean containsKey(Object key);
JavaDoc:
JavaDoc:
boolean java.util.Map.containsValue(Object value)
布尔java.util.Map。containsValue(对象值)
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.如果该映射将一个或多个键映射到指定值,则返回true。更正式地说,如果且仅当此映射包含至少一个到值v的映射,则返回true (value==null ?)v = = null:value.equals(v))。对于映射接口的大多数实现,此操作可能需要在映射大小中使用线性时间。
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:
valueThrows:
ClassCastException - if the value is of an inappropriate type for this map (optional)
ClassCastException—如果该值属于该映射的不适当类型(可选)
NullPointerException - if the specified value is null and this map does not permit null values (optional)
NullPointerException——如果指定的值为空,且此映射不允许空值(可选)
It requires its implementations to implement it, but the "how to" is at its freedom, only to ensure it returns correct.
它需要它的实现来实现它,但是“如何”是它的*,只是为了确保它返回正确。
In HashMap
:
在HashMap:
public boolean containsKey(Object key) { return getNode(hash(key), key) != null;}
It turns out that HashMap
uses hashcode to test if this map contains the key. So it has the benefit of hash algorithm.
原来HashMap使用hashcode来测试这个映射是否包含密钥。它具有哈希算法的优点。
#10
1
Map is the Interface and Hashmap is the class that implements that.
Map是接口,Hashmap是实现这个的类。
So in this implementation you create the same objects
在这个实现中,你创建了相同的对象
#11
1
Map is interface and Hashmap is a class that implements Map Interface
Map是接口,Hashmap是实现Map接口的类
#12
0
HashMap is an implementation of Map so it's quite the same but has "clone()" method as i see in reference guide))
HashMap是Map的一个实现,所以它是完全相同的,但是具有“clone()”方法,我在参考指南中看到)
#13
0
HashMap<String, Object> map1 = new HashMap<String, Object>();Map<String, Object> map2 = new HashMap<String, Object>();
First of all Map
is an interface it has different implementation like - HashMap
, TreeHashMap
, LinkedHashMap
etc. Interface works like a super class for the implementing class. So according to OOP's rule any concrete class that implements Map
is a Map
also. That means we can assign/put any HashMap
type variable to a Map
type variable without any type of casting.
首先,Map是一个具有不同实现的接口,比如HashMap、TreeHashMap、LinkedHashMap等等。根据OOP规则,任何实现Map的具体类都是Map。这意味着我们可以将任何HashMap类型变量分配给Map类型变量,而不需要任何类型的转换。
In this case we can assign map1
to map2
without any casting or any losing of data -
在这种情况下,我们可以将map1分配给map2,而不会造成任何数据的转换或丢失
map2 = map1
#1
347
There is no difference between the objects; you have a HashMap<String, Object>
in both cases. There is a difference in the interface you have to the object. In the first case, the interface is HashMap<String, Object>
, whereas in the second it's Map<String, Object>
. But the underlying object is the same.
物体之间没有区别;两种情况下都有HashMap
The advantage to using Map<String, Object>
is that you can change the underlying object to be a different kind of map without breaking your contract with any code that's using it. If you declare it as HashMap<String, Object>
, you have to change your contract if you want to change the underlying implementation.
使用Map
Example: Let's say I write this class:
比方说我写了这门课:
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...}
The class has a couple of internal maps of string->object which it shares (via accessor methods) with subclasses. Let's say I write it with HashMap
s to start with because I think that's the appropriate structure to use when writing the class.
该类有两个字符串->对象的内部映射,它与子类共享(通过accessor方法)。假设我用hashmap开始,因为我认为这是在编写类时使用的合适结构。
Later, Mary writes code subclassing it. She has something she needs to do with both things
and moreThings
, so naturally she puts that in a common method, and she uses the same type I used on getThings
/getMoreThings
when defining her method:
稍后,Mary编写代码子类化。她有一些她需要做的事情和更多的事情,所以自然她把它放在一个普通的方法中,她使用了我在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...}
Later, I decide that actually, it's better if I use TreeMap
instead of HashMap
in Foo
. I update Foo
, changing HashMap
to TreeMap
. Now, SpecialFoo
doesn't compile anymore, because I've broken the contract: Foo
used to say it provided HashMap
s, but now it's providing TreeMaps
instead. So we have to fix SpecialFoo
now (and this kind of thing can ripple through a codebase).
稍后,我决定实际上,如果我在Foo中使用TreeMap而不是HashMap会更好。我更新Foo,将HashMap更改为TreeMap。现在,SpecialFoo不再编译了,因为我破坏了约定:Foo过去说它提供了HashMaps,但是现在它提供了TreeMaps。所以我们现在必须修复SpecialFoo(这类东西可以通过代码基传播)。
Unless I had a really good reason for sharing that my implementation was using a HashMap
(and that does happen), what I should have done was declare getThings
and getMoreThings
as just returning Map<String, Object>
without being any more specific than that. In fact, barring a good reason to do something else, even within Foo
I should probably declare things
and moreThings
as Map
, not HashMap
/TreeMap
:
除非我有一个很好的理由来分享我的实现使用了HashMap(这确实发生了),否则我应该做的就是声明getThings和getMoreThings作为返回Map
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...}
Note how I'm now using Map<String, Object>
everywhere I can, only being specific when I create the actual objects.
请注意,我现在是如何使用Map
If I had done that, then Mary would have done this:
如果我那样做,玛丽也会这样做:
class SpecialFoo extends Foo { private void doSomething(Map<String, Object> t) { // <== Changed // ... } public void whatever() { this.doSomething(this.getThings()); this.doSomething(this.getMoreThings()); }}
...and changing Foo
wouldn't have made SpecialFoo
stop compiling.
…改变Foo不会让SpecialFoo停止编译。
Interfaces (and base classes) let us reveal only as much as is necessary, keeping our flexibility under the covers to make changes as appropriate. In general, we want to have our references be as basic as possible. If we don't need to know it's a HashMap
, just call it a Map
.
接口(和基类)只允许我们尽可能多地显示所需的内容,保持我们的灵活性,以便进行适当的更改。一般来说,我们希望我们的引用尽可能地基本。如果我们不需要知道它是一个HashMap,就称它为Map。
This isn't a blind rule, but in general, coding to the most general interface is going to be less brittle than coding to something more specific. If I'd remembered that, I wouldn't have created a Foo
that set Mary up for failure with SpecialFoo
. If Mary had remembered that, then even though I messed up Foo
, she would have declared her private method with Map
instead of HashMap
and my changing Foo
's contract wouldn't have impacted her code.
这并不是一个盲目的规则,但一般来说,对最通用的接口进行编码比对更具体的东西进行编码要容易一些。如果我记得的话,我就不会创建一个Foo来设置Mary为SpecialFoo的失败。如果Mary记得,那么即使我把Foo搞砸了,她也会用Map而不是HashMap来声明她的私有方法,而我修改的Foo的契约也不会影响她的代码。
Sometimes you can't do that, sometimes you have to be specific. But unless you have a reason to be, err toward the least-specific interface.
有时候你做不到,有时候你必须具体。但是,除非你有理由这样做,否则最好选择最不特定的界面。
#2
52
Map is an interface that HashMap implements. The difference is that in the second implementation your reference to the HashMap will only allow the use of functions defined in the Map interface, while the first will allow the use of any public functions in HashMap (which includes the Map interface).
Map是HashMap实现的接口。不同的是,在第二个实现中,您对HashMap的引用只允许使用在Map接口中定义的函数,而第一个实现将允许使用HashMap(包括Map接口)中的任何公共函数。
It will probably make more sense if you read Sun's interface tutorial
如果您阅读Sun的界面教程,可能会更有意义。
#3
17
I was just going to do this as a comment on the accepted answer but it got too funky (I hate not having line breaks)
我只是想评论一下大家都接受的答案但是太奇怪了(我讨厌没有换行)
ah, so the difference is that in general, Map has certain methods associated with it. but there are different ways or creating a map, such as a HashMap, and these different ways provide unique methods that not all maps have.
啊,所以区别在于,总的来说,Map有一些与之相关的方法。但是有不同的方法或创建映射,比如HashMap,这些不同的方法提供了独特的方法,而不是所有的映射都有。
Exactly--and you always want to use the most general interface you possibly can. Consider ArrayList vs LinkedList. Huge difference in how you use them, but if you use "List" you can switch between them readily.
确切地说,你总是想用最通用的接口。考虑ArrayList vs LinkedList。你使用它们的方式有很大的不同,但是如果你使用“列表”,你可以很容易地在它们之间切换。
In fact, you can replace the right-hand side of the initializer with a more dynamic statement. how about something like this:
实际上,您可以用更动态的语句替换初始化器的右边。像这样的东西怎么样:
List collection;if(keepSorted) collection=new LinkedList();else collection=new ArrayList();
This way if you are going to fill in the collection with an insertion sort, you would use a linked list (an insertion sort into an array list is criminal.) But if you don't need to keep it sorted and are just appending, you use an ArrayList (More efficient for other operations).
这样,如果您要用插入排序填充集合,您将使用一个链表(数组列表中的插入排序是犯罪的)。但是,如果您不需要对它进行排序和添加,您可以使用ArrayList(其他操作更有效)。
This is a pretty big stretch here because collections aren't the best example, but in OO design one of the most important concepts is using the interface facade to access different objects with the exact same code.
这是一个很大的扩展,因为集合不是最好的例子,但是在OO设计中最重要的概念之一是使用接口facade来访问具有完全相同代码的不同对象。
Edit responding to comment:
编辑回复评论:
As for your map comment below, Yes using the "Map" interface restricts you to only those methods unless you cast the collection back from Map to HashMap (which COMPLETELY defeats the purpose).
对于下面的map注释,如果使用“map”接口,那么只能使用这些方法,除非将集合从map转换回HashMap(这完全违背了目的)。
Often what you will do is create an object and fill it in using it's specific type (HashMap), in some kind of "create" or "initialize" method, but that method will return a "Map" that doesn't need to be manipulated as a HashMap any more.
通常,您要做的是创建一个对象并使用它的特定类型(HashMap)填充它,使用某种“create”或“initialize”方法,但是该方法将返回一个“Map”,不再需要作为HashMap来操作。
If you ever have to cast by the way, you are probably using the wrong interface or your code isn't structured well enough. Note that it is acceptable to have one section of your code treat it as a "HashMap" while the other treats it as a "Map", but this should flow "down". so that you are never casting.
如果您需要强制转换,您可能使用了错误的接口,或者您的代码结构不够好。请注意,您的代码中有一部分将其视为“HashMap”,而另一部分将其视为“Map”,这是可以接受的,但这应该是“向下”的。这样你就不会选角了。
Also notice the semi-neat aspect of roles indicated by interfaces. A LinkedList makes a good stack or queue, an ArrayList makes a good stack but a horrific queue (again, a remove would cause a shift of the entire list) so LinkedList implements the Queue interface, ArrayList does not.
还要注意接口指示的角色的半整洁方面。一个LinkedList创建了一个很好的堆栈或队列,一个ArrayList创建了一个很好的堆栈,但是一个很可怕的队列(同样,删除会导致整个列表的移位),所以LinkedList实现了队列接口,而ArrayList则没有。
#4
16
Map having following implementations,
地图在实现后,
-
HashMap
Map m = new HashMap();
HashMap m = new HashMap();
-
LinkedHashMap
Map m = new LinkedHashMap();
LinkedHashMap m =新的LinkedHashMap();
-
Tree Map
Map m = new TreeMap();
树形图m = new TreeMap();
-
WeakHashMap
Map m = new WeakHashMap();
WeakHashMap m = new WeakHashMap();
Suppose you have created one method (It's just spudo code).
假设您已经创建了一个方法(它只是spudo代码)。
public void HashMap getMap(){ return map;}
Suppose you project requirement are changing each time as follows,
假设您的项目需求每次都在变化,如下所示,
- Method should return map contents - Need to return
HashMap
. - 方法应该返回映射内容——需要返回HashMap。
- Method should return map key's in insertion order - Need to change return type
HashMap
toLinkedHashMap
. - 方法应该按插入顺序返回映射键——需要将返回类型HashMap更改为LinkedHashMap。
- Method should return map key's in sorted order - Need to change return type
LinkedHashMap
toTreeMap
. - 方法应该以排序的顺序返回映射键——需要将返回类型LinkedHashMap更改为TreeMap。
If your method returning Specific classes instead of Map
interface you have to change return type of getMap()
method each time.
如果方法返回特定的类而不是映射接口,那么每次都必须更改getMap()方法的返回类型。
But, If you use polymorphism feature of java, Instead of returning specific class used interface Map
, It leads code reusability and less impact if any requirement change.
但是,如果您使用java的多态性特性,而不是返回特定的类used interface Map,它将导致代码的可重用性,并且在任何需求更改时影响更小。
#5
12
As noted by TJ Crowder and Adamski, one reference is to an interface, the other to a specific implementation of the interface. According to Joshua Block, you should always attempt to code to interfaces, to allow you to better handle changes to underlying implementation - i.e. if HashMap suddenly was not ideal for your solution and you needed to change the map implementation, you could still use the Map interface, and change the instantiation type.
正如TJ Crowder和Adamski所指出的,一个是对接口的引用,另一个是对接口的特定实现的引用。约书亚说,你应该尝试代码界面,让你更好地处理更改底层实现,即如果HashMap突然没有适合您的解决方案,您需要改变地图的实现,您仍然可以使用地图界面,改变实例化类型。
#6
8
In your second example the "map" reference is of type Map
, which is an interface implemented by HashMap
(and other types of Map
). This interface is a contract saying that the object maps keys to values and supports various operations (e.g. put
, get
). It says nothing about the implementation of the Map
(in this case a HashMap
).
在第二个示例中,“map”引用的类型是map,它是HashMap(和其他类型的map)实现的接口。该接口是一个约定,表示对象将键映射到值并支持各种操作(例如put、get)。它没有说明映射的实现(在本例中是HashMap)。
The second approach is generally preferred as you typically wouldn't want to expose the specific map implementation to methods using the Map
or via an API definition.
第二种方法通常是首选的,因为您通常不想使用映射或API定义来公开特定的映射实现。
#7
8
Map is the static type of map, while HashMap is the dynamic type of map. This means that the compiler will treat your map object as being one of type Map, even though at runtime, it may point to any subtype of it.
Map是Map的静态类型,HashMap是Map的动态类型。这意味着编译器将把映射对象视为类型映射,即使在运行时,它可能指向它的任何子类型。
This practice of programming against interfaces instead of implementations has the added benefit of remaining flexible: You can for instance replace the dynamic type of map at runtime, as long as it is a subtype of Map (e.g. LinkedHashMap), and change the map's behavior on the fly.
这种针对接口而不是实现编程的实践还有一个额外的好处:例如,您可以在运行时替换动态映射类型,只要它是映射的子类型(例如LinkedHashMap),并动态地更改映射的行为。
A good rule of thumb is to remain as abstract as possible on the API level: If for instance a method you are programming must work on maps, then it's sufficient to declare a parameter as Map instead of the stricter (because less abstract) HashMap type. That way, the consumer of your API can be flexible about what kind of Map implementation they want to pass to your method.
一个很好的经验法则是在API级别上尽可能保持抽象:如果您正在编程的方法必须处理映射,那么将参数声明为映射就足够了,而不是更严格的HashMap类型(因为不太抽象)。这样,您的API的使用者可以灵活地了解他们想要传递给您的方法的地图实现类型。
#8
3
You create the same maps.
创建相同的映射。
But you can fill the difference when you will use it. With first case you'll be able to use special HashMap methods (but I don't remember anyone realy useful), and you'll be able to pass it as a HashMap parameter:
但是您可以在使用它的时候补上差额。对于第一种情况,您可以使用特殊的HashMap方法(但我不记得有什么有用的方法),并且可以将其作为HashMap参数传递:
public void foo (HashMap<String, Object) { ... }...HashMap<String, Object> m1 = ...;Map<String, Object> m2 = ...;foo (m1);foo ((HashMap<String, Object>)m2);
#9
2
Adding to the top voted answer and many ones above stressing the "more generic, better", I would like to dig a little bit more.
在上面的投票答案和许多强调“更一般,更好”的答案中,我想再深入一点。
Map
is the structure contract while HashMap
is an implementation providing its own methods to deal with different real problems: how to calculate index, what is the capacity and how to increment it, how to insert, how to keep the index unique, etc.
Map是结构契约,HashMap是实现,提供了自己的方法来处理不同的实际问题:如何计算索引、容量是什么、如何增加索引、如何插入、如何保持索引惟一等等。
Let's look into the source code:
让我们看看源代码:
In Map
we have the method of containsKey(Object key)
:
在Map中我们有containsKey(Object key)方法:
boolean containsKey(Object key);
JavaDoc:
JavaDoc:
boolean java.util.Map.containsValue(Object value)
布尔java.util.Map。containsValue(对象值)
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.如果该映射将一个或多个键映射到指定值,则返回true。更正式地说,如果且仅当此映射包含至少一个到值v的映射,则返回true (value==null ?)v = = null:value.equals(v))。对于映射接口的大多数实现,此操作可能需要在映射大小中使用线性时间。
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:
valueThrows:
ClassCastException - if the value is of an inappropriate type for this map (optional)
ClassCastException—如果该值属于该映射的不适当类型(可选)
NullPointerException - if the specified value is null and this map does not permit null values (optional)
NullPointerException——如果指定的值为空,且此映射不允许空值(可选)
It requires its implementations to implement it, but the "how to" is at its freedom, only to ensure it returns correct.
它需要它的实现来实现它,但是“如何”是它的*,只是为了确保它返回正确。
In HashMap
:
在HashMap:
public boolean containsKey(Object key) { return getNode(hash(key), key) != null;}
It turns out that HashMap
uses hashcode to test if this map contains the key. So it has the benefit of hash algorithm.
原来HashMap使用hashcode来测试这个映射是否包含密钥。它具有哈希算法的优点。
#10
1
Map is the Interface and Hashmap is the class that implements that.
Map是接口,Hashmap是实现这个的类。
So in this implementation you create the same objects
在这个实现中,你创建了相同的对象
#11
1
Map is interface and Hashmap is a class that implements Map Interface
Map是接口,Hashmap是实现Map接口的类
#12
0
HashMap is an implementation of Map so it's quite the same but has "clone()" method as i see in reference guide))
HashMap是Map的一个实现,所以它是完全相同的,但是具有“clone()”方法,我在参考指南中看到)
#13
0
HashMap<String, Object> map1 = new HashMap<String, Object>();Map<String, Object> map2 = new HashMap<String, Object>();
First of all Map
is an interface it has different implementation like - HashMap
, TreeHashMap
, LinkedHashMap
etc. Interface works like a super class for the implementing class. So according to OOP's rule any concrete class that implements Map
is a Map
also. That means we can assign/put any HashMap
type variable to a Map
type variable without any type of casting.
首先,Map是一个具有不同实现的接口,比如HashMap、TreeHashMap、LinkedHashMap等等。根据OOP规则,任何实现Map的具体类都是Map。这意味着我们可以将任何HashMap类型变量分配给Map类型变量,而不需要任何类型的转换。
In this case we can assign map1
to map2
without any casting or any losing of data -
在这种情况下,我们可以将map1分配给map2,而不会造成任何数据的转换或丢失
map2 = map1