0

代码:

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

4

10 回答 10

4

这与冲突链接无关:您正在用a新值替换旧值。

地图保留唯一的键。当两个不同的键碰巧基于特定的哈希函数获得相同的哈希值时,哈希数据结构中将发生冲突/链接。或者在 java 中,您可以显式创建一个返回相同值的对象hashCode()

如果您想为一个键映射多个值,那么您需要使用不同的数据结构/类。

于 2012-08-06T04:28:27.667 回答
2

请参阅 java 文档put

将指定值与此映射中的指定键关联(可选操作)。如果映射先前包含键的映射,则旧值将替换为指定值。(当且仅当 m.containsKey(k) 返回 true 时,映射 m 被称为包含键 k 的映射。)

当两个不同的键出现相同的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; 但是您不能从映射键和值的输出中解释这一点。

于 2012-08-06T04:28:57.573 回答
2

就像其他人已经建议的那样,对于您的情况,没有碰撞之类的东西。

这仅仅是因为 Hashmap 只接受一个唯一的键。

但是,如果您希望密钥不是唯一的,您可以有其他选择,例如Google Guava MultimapApache Multimap

使用 Google 库的示例:

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!)
}
}
于 2012-08-06T04:33:19.030 回答
1

第二个put()简单地覆盖了第一个put()写的内容。没有链接。

于 2012-08-06T04:28:36.373 回答
1

Secondput替换 first ,因此在Hashmapput中只有一个键为“a”的值。

所以你的地图只包含

map.put("a", "v");
于 2012-08-06T04:28:38.537 回答
1

现在,根据我的理解,由于两个 put 案例中的键值是相同的,即 a,因此必然会发生冲突,因此会发生链接。[如果我错了,请纠正我]。

你错了。这不是地图的工作方式。考虑使用 Google 的 Guava 库中的MultiMap

你总是可以自己动手:

Map<String, ArrayList<String>>();
于 2012-08-06T04:30:14.157 回答
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"));
}
于 2012-08-06T04:33:52.560 回答
1

HashMaps 中使用的散列算法一开始就非常模糊。在内部,HashMap 只不过是一个带有索引的数组。这里的索引通常称为“hashValue”。由于 hashValue 是数组中元素的索引,它必须小于 HashMap 本身的大小。HashMap 的哈希算法将键的哈希码转换为 hashValue。这是 Map 存储条目(键值对)的地方。

当一个元素被放入一个 Map 时,它会从元素键的 hashcode 中生成 hashValue,并将 Entry 存储到该索引处的数组中,也就是 hashValue。现在,散列算法只能在一定程度上有效,即我们永远不能保证为两个不同的键生成的 hashValue 总是不同的。在两种情况下可能相同:1)密钥相同(如您的情况) 2)密钥不同,但为两个密钥生成的 hashValue 相同。

我们根本无法在数组中的 hashValue 位置替换 Entry 的值,因为这将违反第二个条件,这是非常有效的。这就是 equals() 出现的地方。现在,HashMap 检查新键与该索引条目中存在的键是否相等。如果两个键相同,则表示替换,否则为冲突,HashMap 使用适当的冲突技术。

现在,如果您想要为特定键放置的所有值的列表,请考虑使用复合映射 HashMap<String, List<String>>

于 2012-08-06T04:54:18.023 回答
0

您尝试放入的两个键HashMap具有相同的HashCode. 因此,第一个值被覆盖,您最终将在HashMap.

您可以通过覆盖他们的hashCode()方法将两个相似的对象放在同一个 HashMap 中。

于 2012-08-06T05:12:42.323 回答
0

关于使用 HashMap 时实际发生链接的时间的进一步说明:

HashMap 的 Java 实现将覆盖键或将对象链接到它,具体取决于以下内容:

  1. 您将对象foo作为键,哈希码 X 放入地图
  2. 您将另一个具有相同哈希码 X 的对象栏(作为键..)放入地图中
  3. 由于哈希值相同,因此算法需要将对象bar放在已存储foo的同一索引上。然后它会查询foo的equals方法,以确定是否应该将bar链接foo(即foo.next()将变为bar)或用 bar覆盖foo:

    3.1.如果equals返回true,则foo & bar要么是同一个对象,要么它们在语义上是相同的,并且将发生覆盖而不是链接。

    3.2. 如果 equals 返回 false,则foobar被视为两个不同的实体,并且将发生链接。如果您随后打印您的 HashMap,您将看到foobar

于 2017-10-12T15:16:15.237 回答