可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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
?
回答1:
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.
回答2:
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.
回答3:
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. ;)
回答4:
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
回答5:
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.
回答6:
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.
回答7:
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