代码:
public static void main(String[] args) {
Map<String,String> map= new HashMap<String,String>();
map.put("a", "s");
map.put("a", "v");
System.out.println(map.get("a"));
}
现在,根据我的理解,由于put
情况下的键值相同即a
,因此必然会发生冲突,因此会发生链接。 [纠正我,如果我错了]。
现在,如果我想检索映射到键值a
的所有值的列表,我该如何获取它?
现在我的println
仅打印v
。
答案 0 :(得分:4)
这与 collision 或 chaining 无关:您将a
的旧值替换为新值。
地图保留唯一键。当两个不同的键碰巧基于特定的散列函数获得相同的散列值时,将在散列数据结构中发生冲突/链接。或者在java中,您可以显式创建一个为hashCode()
返回相同值的对象。
如果要为键创建多个值,则需要使用不同的数据结构/类。
答案 1 :(得分:2)
请参阅{docner for put
将指定的值与此映射中的指定键相关联(可选操作)。 如果地图以前包含该键的映射,则旧值将替换为指定的值。(当且仅当m.containsKey时,地图m包含键k的映射。 k)将返回true。)
当两个不同的键出现相同的hashcode
而不是两个相同的键时,会发生冲突。
class StringKey {
String text;
public StringKey() {
text = "";
}
public StringKey(String text) {
this.text = text;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
@Override
public int hashCode() {
if (text != null) {
text.substring(0, 1).hashCode();
}
return 0;
}
@Override
public boolean equals(Object o) {
if (o instanceof StringKey) {
return ((StringKey) o).getText().equals(this.getText());
}
return false;
}
public static void main(String[] args) {
Map<StringKey, String> map = new HashMap<StringKey, String>();
StringKey key1 = new StringKey("a");
StringKey key2 = new StringKey("b");
map.put(key1, "s");
map.put(key2, "v");
System.out.println(map.get(key1));
System.out.println(key1.hashCode() + " " + key2.hashCode() + " " + key1.equals(key2));
}
}
输出
s
0 0 false
现在这会导致collision
;但你无法从地图键和值的输出中解释这一点。
答案 2 :(得分:2)
像其他人已经建议的那样,对你的案子来说没有碰撞这样的事情。
这只是因为Hashmap只接受一个唯一的密钥。
但是,如果您希望密钥不唯一,则可以选择其他方式,例如Google Guava Multimap或Apache Multimap
使用Google lib的示例:
public class MutliMapTest {
public static void main(String... args) {
Multimap<String, String> myMultimap = ArrayListMultimap.create();
// Adding some key/value
myMultimap.put("Fruits", "Bannana");
myMultimap.put("Fruits", "Apple");
myMultimap.put("Fruits", "Pear");
myMultimap.put("Vegetables", "Carrot");
// Getting the size
int size = myMultimap.size();
System.out.println(size); // 4
// Getting values
Collection<string> fruits = myMultimap.get("Fruits");
System.out.println(fruits); // [Bannana, Apple, Pear]
Collection<string> vegetables = myMultimap.get("Vegetables");
System.out.println(vegetables); // [Carrot]
// Iterating over entire Mutlimap
for(String value : myMultimap.values()) {
System.out.println(value);
}
// Removing a single value
myMultimap.remove("Fruits","Pear");
System.out.println(myMultimap.get("Fruits")); // [Bannana, Pear]
// Remove all values for a key
myMultimap.removeAll("Fruits");
System.out.println(myMultimap.get("Fruits")); // [] (Empty Collection!)
}
}
答案 3 :(得分:1)
第二个put()
只是覆盖了第一个put()
所写的内容。没有链接。
答案 4 :(得分:1)
答案 5 :(得分:1)
现在,按照我的理解,既然是put的情况下的键值 是相同的,即a,碰撞必然发生,因此链接 发生。 [纠正我,如果我错了]。
你错了。那不是Map如何运作的。考虑使用Google的Guava库中的MultiMap。
你可以随时自己动手:
Map<String, ArrayList<String>>();
答案 6 :(得分:1)
您必须按照以下方式制作HashMap
public static void main(String[] args) {
HashMap<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>();
if ( map.get("a") == null ){
map.put("a", new ArrayList<String>());
}
ArrayList<String> innerList = map.get("a");
innerList.add("s");
innerList.add("v");
map.put("a",innerList);
System.out.println(map.get("a"));
}
答案 7 :(得分:1)
HashMaps中使用的哈希算法在第一时间是非常模糊的。在内部,HashMap只是一个带索引的数组。这里的索引通常称为'hashValue'。由于hashValue是数组中元素的索引,因此它必须小于HashMap本身的大小.HashMap的散列算法将密钥的哈希码转换为hashValue。这是Map存储Entry(键值对)的地方。
当一个元素放入Map时,它会从元素键的hashcode生成hashValue,并将Entry存储到该索引处的数组中,该索引只是hashValue。 现在,散列算法只能在一定程度上有效,也就是说我们永远无法保证为两个不同的密钥生成的hashValue总是不同的。在两种情况下可能相同: 1)键是相同的(如你的情况) 2)密钥不同,但为两个密钥生成的hashValue是相同的。
我们根本无法替换数组中hashValue位置的Entry值,因为这会违反第二个条件,这是非常有效的。这是equals()进入画面的地方。现在,HashMap检查新密钥与该索引的Entry中存在的密钥之间的相等性。如果两个键都相同则意味着替换,否则它就是碰撞,而HashMap使用适当的碰撞技术。
现在,如果您想要为特定键添加的所有值的列表,请考虑使用复合映射
HashMap<String, List<String>>
。
答案 8 :(得分:0)
您尝试放入HashMap
的两个密钥都具有相同的HashCode
。因此,第一个值会被覆盖,最终只会在HashMap
中包含一个值。
您可以通过覆盖hashCode()
方法将两个相似的对象放在同一个HashMap中。
答案 9 :(得分:0)
关于在使用HashMap时实际发生链接的进一步说明:
HashMap的Java实现将覆盖一个键或链一个对象,具体取决于以下内容:
由于哈希值相同,算法需要放入 对象 bar 在已存储 foo 的同一索引上。然后它会参考 foo 的 equals 方法,以确定它是否链 bar 到 foo (即 foo.next()将成为 bar )或覆盖 foo with bar:
3.1。如果等于返回true, foo &amp; bar 是相同的对象,或者它们在语义上是相同的,并且将覆盖而不是链接。
3.2。如果equals返回false, foo &amp; bar 被视为两个不同的实体,并将进行链接。如果您随后打印了HashMap,那么您将同时看到 foo 和 bar 。