在哈希表中,是否可能为相同的键拥有多个值?如果不行,你能推荐任何可用的类或接口吗?
在哈希表中,是否可能为相同的键拥有多个值?如果不行,你能推荐任何可用的类或接口吗?
不是的。这就是哈希表的设计思想。
但是,你可以使用Map<YourKeyObject, List<YourValueObject>>
自己实现,并编写一些实用方法来创建列表(如果不存在),或者使用Google Collections中的Multimap
。
String key = "hello";
Multimap<String, Integer> myMap = HashMultimap.create();
myMap.put(key, 1);
myMap.put(key, 5000);
System.out.println(myMap.get(key)); // prints either "[1, 5000]" or "[5000, 1]"
myMap = ArrayListMultimap.create();
myMap.put(key, 1);
myMap.put(key, 5000);
System.out.println(myMap.get(key)); // always prints "[1, 5000]"
Multimap
不是自制解决方案的完全等价物; Hashtable
同步其所有方法,而Multimap
没有这样的保证。这意味着如果您在多个线程上使用Multimap
,可能会遇到问题。如果您只在一个线程上使用映射,则不会有任何区别(并且您应该使用HashMap
而不是Hashtable
)。
哈希表的值是对象,因此您可以存储列表。
Hashtable
类接受单个键的单个值。以下是尝试将多个值关联到单个键的示例:Hashtable<String, String> ht = new Hashtable<String, String>();
ht.put("Answer", "42");
ht.put("Hello", "World"); // First value association for "Hello" key.
ht.put("Hello", "Mom"); // Second value association for "Hello" key.
for (Map.Entry<String, String> e : ht.entrySet()) {
System.out.println(e);
}
"World"
,"Mom"
)包含到单个键("Hello"
)中,我们最终得到在 Hashtable
中打印条目的以下结果:Answer=42
Hello=Mom
"Hello"
和"World"
的键值对不在Hashtable
中,只有第二个"Hello"
和"Mom"
条目在Hashtable
中。这表明在Hashtable
中不能将多个值与单个键关联。"
Multimap
,来自Google Collections。Multimap<String, String> mm = HashMultimap.create();
mm.put("Answer", "42");
mm.put("Hello", "World");
mm.put("Hello", "Mom");
for (Map.Entry<String, String> e : mm.entries()) {
System.out.println(e);
}
Hashtable
的示例类似,但行为有很大不同——Multimap
允许将多个值与单个键相关联。执行上述代码的结果如下:Answer=42
Hello=Mom
Hello=World
不是再给出另一个多映射答案,我会问为什么你想要这样做?
这些多个值是否相关联?如果是,那么最好创建一个数据结构来容纳它们。如果不是,那么也许使用单独的映射更合适。
你是否将它们放在一起,以便可以根据键迭代它们?您可能需要寻找替代索引数据结构,例如SkipList。
Map<Object, List<Object>> multiMap = new HashMap<Object, List<Object>>();
添加:
public void add(String key, Object o) {
List<Object> list;
if (multiMap.containsKey(key)) {
list = multiMap.get(key);
list.add(o);
} else {
list = new ArrayList<Object>();
list.add(o);
multiMap.put(key, list);
}
}
Multimap
,它可以将多个值映射到同一个键上。
Google Collections(更新:Guava)库包含了一种实现,可能是你最好的选择。
编辑:当然,你可以像Eric建议那样,在你的Hashtable(或Map,更普遍地说)中将Collection作为一个值存储,但这意味着你自己编写不必要的样板代码。当使用像Google Collections这样的库时,它会为您处理低级的“管道”问题。查看这个很好的例子,了解如何通过使用Multimap而不是普通Java Collections类来简化代码。没有任何答案表明我首先会怎么做。
我在面向对象编程方面获得的最大提升是当我决定在似乎稍微有用的情况下总是创建另一个类时——这就是我从这种模式中学到的东西之一。
几乎所有时候,我发现我正在尝试放入哈希表中的对象之间存在关系。往往情况下,有空间可以创建一个类——甚至可能只需要一个或两个方法。
事实上,我经常发现我甚至不需要一个 HashMap 类型的结构——一个简单的 HashSet 就足够了。
你存储为主键的项可以成为一个新对象的标识符——因此,你可以创建 equals 和 hash 方法只引用那个对象(eclipse 可以轻松地为你创建 equals 和 hash 方法)。这样,新对象将完全像原始对象一样保存、排序和检索,然后使用属性来存储其他项。
大多数时候,当我这样做时,我发现还有一些方法也适合放在那里,然后在我意识到应该一直存在一个完整的对象之前,我就把一堆垃圾清除出我的代码。
为了使它更像“初步步骤”,我经常创建包含在原始类中的新类——有时甚至在方法中包含该类,如果以那种方式进行作用域限定是有意义的——然后随着它变得更加清晰应该成为一级类时,我就将其移动。
简单易懂。不要使用 Hashtable<Key, Value>
,而是使用 Hashtable<Key, Vector<Value>>
。