当通过 Map.put(K, V) 添加值时,是否必须通过 Map.get(K) 返回相同的实例?

发布于 2024-10-17 20:34:13 字数 1348 浏览 2 评论 0原文

假设您有以下代码:

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 value v such that (key==null ? k==null : key.equals(k)), then this method returns v; otherwise it returns null. (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 to null. The containsKey operation may be used to distinguish these two cases.

Parameters:

key - the key whose associated value is to be returned

Returns:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

得不到的就毁灭 2024-10-24 20:34:13

如果你问是否可以打破这种关系,我想答案是“可以”。例如,如果您正在实现一个充当持久缓存的 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.

等往事风中吹 2024-10-24 20:34:13

如果您将 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.

じ违心 2024-10-24 20:34:13

javadoc 没有明确说明(或限制)您放入映射中的值在物理上等于已放入其中的值。
所以我敢说没有100%的保证,但一定是这样。
您可能会假设:

Map<Foo,Bar> map = new HashMap<Foo,Bar>();
Foo foo = new Foo();
Bar bar = new Bar();
map.put(foo, bar);

System.out.println( bar.equals( map.get(foo) ) ); // ==> Should be guaranteed
System.out.println( bar == map.get(foo) );        // ==> no guarantee

理论上您可以创建一个在不同 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:

Map<Foo,Bar> map = new HashMap<Foo,Bar>();
Foo foo = new Foo();
Bar bar = new Bar();
map.put(foo, bar);

System.out.println( bar.equals( map.get(foo) ) ); // ==> Should be guaranteed
System.out.println( bar == map.get(foo) );        // ==> no guarantee

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 necessarly bar == 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. ;)

西瓜 2024-10-24 20:34:13

如果您正在实现自己的 Map 版本,那么您不需要返回相同的对象实例。文档和语言中没有任何内容要求您的实现返回相同的对象实例。

当且仅当代码中的某些库或其他部分做出了返回值将是相同对象实例的假设(虽然通常是合理的,但没有根据)时,您的代码可能会中断。在这种情况下,请不要将 Map 的实现传递给该代码。

Patient: Doctor, it hurts when I do this
Doctor: Well, don't do that

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.

Patient: Doctor, it hurts when I do this
Doctor: Well, don't do that
你与清晨阳光 2024-10-24 20:34:13

当然,它将是同一个实例。否则Map就没用了。

不过,唯一的例外是多线程应用程序,其中其他线程可以在调用 putget 之间将任意值赋给同一键。


编辑 正如 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 and get.


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 and original == copy is false. In this case I think Map can store copy instead of original.

逆流 2024-10-24 20:34:13

请注意,它表示键映射到的“值”,而不是“引用”或“实例”。当您听到“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.

还在原地等你 2024-10-24 20:34:13
class Foo{

}
class Bar{

}
public class MapDemo {
    public static void main(String[] args) {
        Map<Foo,Bar> map = new HashMap<Foo,Bar>();
        Foo foo = new Foo();
        Bar bar = new Bar();
        map.put(foo, bar);
        System.out.println(bar == map.get(foo));
    }
}

返回true

HashMap 实现Map 但没有这样的编写。

  /**
  137        * Returns the value of the mapping with the specified key.
  138        * 
  139        * @param key
  140        *            the key.
  141        * @return the value of the mapping with the specified key, or {@code null}
  142        *         if no mapping for the specified key is found.
  143        */

但几乎每个实现都会这样做,我的意思是它维护相同的对象

class Foo{

}
class Bar{

}
public class MapDemo {
    public static void main(String[] args) {
        Map<Foo,Bar> map = new HashMap<Foo,Bar>();
        Foo foo = new Foo();
        Bar bar = new Bar();
        map.put(foo, bar);
        System.out.println(bar == map.get(foo));
    }
}

Returns true

HashMap implements Map but there is nothing written such.

  /**
  137        * Returns the value of the mapping with the specified key.
  138        * 
  139        * @param key
  140        *            the key.
  141        * @return the value of the mapping with the specified key, or {@code null}
  142        *         if no mapping for the specified key is found.
  143        */

But almost each implementation does this, I mean it maintains the same Object

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文