当通过 Map.put(K, V) 添加值时,是否必须通过 Map.get(K) 返回相同的实例?
假设您有以下代码:
Map<Foo, Bar> map = new HashMap<Foo, Bar>();
Foo foo = new Foo();
Bar bar = new Bar();
map.put(foo, bar);
Bar barReturned = map.get(foo);
Java 是否要求 barReturned == bar
?也就是说,Java 是否要求 barReturned 与
bar
是相同的实例?如果不是,那么期望什么语义?
Javadoc 建议 barReturned = = bar
一定是真的,但我不是 100% 确定:
V get(对象键)
返回指定键映射到的值,如果此映射不包含该键的映射,则返回
null
。更正式地说,如果此映射包含从键
k
到值v
的映射,使得(key==null ? k==null : key.equals(k))
,则该方法返回v
;否则返回null
。 (最多可以有一个这样的映射。)如果此映射允许
null
值,则返回值 null 不一定表明该映射不包含该键的映射;映射也可能显式地将键映射到null
。可以使用 containsKey 操作来区分这两种情况。参数:
key
- 要返回关联值的键退货:
指定键映射到的值,如果此映射不包含该键的映射,则为
null
(强调我的)
编辑:我了解 的实现与标准库捆绑在一起的 Map
遵循 barReturned == bar
语义。我想知道的是,根据文档,这种行为是否是必需的。例如,如果我编写自己的实现 Map
的类,我是否也必须遵守这些语义?
Suppose you have this code:
Map<Foo, Bar> map = new HashMap<Foo, Bar>();
Foo foo = new Foo();
Bar bar = new Bar();
map.put(foo, bar);
Bar barReturned = map.get(foo);
Does Java require that barReturned == bar
? That is, does Java require that barReturned
be the same instance as bar
? If not, what semantics are expected?
The Javadoc suggests that barReturned == bar
must be true, but I'm not 100% sure:
V get(Object key)
Returns the value to which the specified key is mapped, or
null
if this map contains no mapping for the key.More formally, if this map contains a mapping from a key
k
to a valuev
such that(key==null ? k==null : key.equals(k))
, then this method returnsv
; otherwise it returnsnull
. (There can be at most one such mapping.)If this map permits
null
values, then a return value of null does not necessarily indicate that the map contains no mapping for the key; it's also possible that the map explicitly maps the key tonull
. The containsKey operation may be used to distinguish these two cases.Parameters:
key
- the key whose associated value is to be returnedReturns:
THE VALUE TO WHICH THE SPECIFIED KEY IS MAPPED, or
null
if this map contains no mapping for the key
(Emphasis mine)
Edit: I understand that the implementations of Map
that come bundled with the standard library adhere to the barReturned == bar
semantics. What I want to know is whether or not this behavior is required as per the documentation. For example, must I also adhere to these semantics if I write my own class that implements Map
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
如果你问是否可以打破这种关系,我想答案是“可以”。例如,如果您正在实现一个充当持久缓存的 Map,则如果一段时间内不使用特定值,则可能会将其写入磁盘,然后稍后重新加载。在这种情况下你不会有参考平等,但没关系。显然,您希望记录与标准行为的任何偏差,但我认为这不超出地图合理使用的范围。
If you are asking whether you can break that relation, i think the answer is "yes". for instance, if you were implementing a Map which acted like a persistent cache, a specific value may be written to disk if not used in a while, then reloaded later. you will not have reference equality in that situation, but that's okay. obviously, you would want to document any deviations from standard behavior, but i don't think this is out of the realm of a reasonable usage of a Map.
如果您将 javadoc 中使用的术语值解释为对映射中对象的引用,则意味着您始终需要返回与放入映射,你就会有 == 平等。那么它就变成了文档中使用的术语“值”的定义问题。
If you interpret the term value used in the javadocs as the reference to the object in the map it would imply that you always need to return the same reference as you put in the map and you would have == equality. Then it becomes more of a question of the definition of the term value used in the docs.
javadoc 没有明确说明(或限制)您放入映射中的值在物理上等于已放入其中的值。
所以我敢说没有100%的保证,但一定是这样。
您可能会假设:
理论上您可以创建一个在不同 JVM 上共享和同步的集群 Map 实现,在这种情况下,不可能(或至少非常困难)获得相同的物理实例。
我的观点是,在您的实现中,您应该保证
bar.equals( map.get(foo) )
但不一定是bar == map.get(foo)
。但是,只要您清楚地记录并声明以上两者都不能得到保证,您就可以使用 Map 实现执行您想要的操作。 ;)
The javadoc does not sate (or limit) it clearly that values that you put in the map are physically equal to those that have been put into it.
So I'd dare to say that there is no 100% guarantee, that it must be so.
You probably could assume that:
You could in theory create a clustered Map implementation that is shared and synchronized on different JVMs, in this case it would be impossible (or at least really difficult) to obtain the same physical instance.
My opinion is that in your implementation you should guarantee that
bar.equals( map.get(foo) )
but not necessarlybar == map.get(foo)
.However as long as you clearly document and state that both of the above is not guaranteed, you can do what you want with your Map implementation. ;)
如果您正在实现自己的 Map 版本,那么您不需要返回相同的对象实例。文档和语言中没有任何内容要求您的实现返回相同的对象实例。
当且仅当代码中的某些库或其他部分做出了返回值将是相同对象实例的假设(虽然通常是合理的,但没有根据)时,您的代码可能会中断。在这种情况下,请不要将 Map 的实现传递给该代码。
If you're implementing your own version of Map, yes you don't need to return the same object instance. There is nothing in the doc and language that requires your implementation to return the same object instance.
Your code might break if and only if there is some library or other parts of your code that made the (unwarranted, though generally reasonable) assumption that the return value will be the same object instance. In this case, well, just don't pass your implementation of Map to that code.
当然,它将是同一个实例。否则
Map
就没用了。不过,唯一的例外是多线程应用程序,其中其他线程可以在调用
put
和get
之间将任意值赋给同一键。编辑 正如 Adam 在评论中指出的那样,他有一个特殊情况,即他的 Map 实现可以重新创建传入对象并使用它们的副本。
original.equals(copy)
意义上的副本为 true,original == copy
为 false。在这种情况下,我认为 Map 可以存储副本而不是原始文件。Of course, it will be the same instance. Otherwise
Map
would be useless.Though, the only exception to this is multi-threaded application, where other thread can put arbitrary value to the same key in between your calls to
put
andget
.Edit As Adam pointed out in comments, he have special case where his implementation of Map can recreate incoming objects and use their copies instead. Copies in the sense
original.equals(copy)
is true andoriginal == copy
is false. In this case I think Map can store copy instead of original.请注意,它表示键映射到的“值”,而不是“引用”或“实例”。当您听到“value”时,它暗示了 Object.equals() 语义。您无需担心。
Note it says the "value" to which the key is mapped, not the "reference" or "instance." When you hear "value", it suggests Object.equals() semantics. You have nothing to worry about.
返回true
HashMap
实现Map
但没有这样的编写。但几乎每个实现都会这样做,我的意思是它维护相同的对象
Returns true
HashMap
implementsMap
but there is nothing written such.But almost each implementation does this, I mean it maintains the same Object