问答题 用自定义类型作为HashMap或HashTable的key需要注意哪些问题
【正确答案】
【答案解析】HashMap与HashTable是用来存放键值对的一种容器,在使用这两个容器时有一个限制:不能用来存储重复的键。也就是说,每个键只能唯一映射一个值,当有重复的键时,不会创建新的映射关系,而会使用先前的键值。为了更好地说明这个问题,我们首先来看一段示例代码:
import Java.util.*;
public class Test{
public static void test1(){
System.out.println("Use user defined class as key:");
HashMap<String, String>hm=new HashMap<String, String>();
hm.put("aaa", "bbb");
hm.put("aaa", "ccc");
Iterator iter=hm.entrySet().iterator();
while(iter.hasNext()){
Map.Entry entry=(Map.Entry)iter.next();
String key=(String)entry.getKey();
String val=(String)entry.getValue();
System.out.println(key+" "+val);
}
}
public static void main(String args[]){
test1();
}
}
程序运行结果为:
Use user defined class as key:
aaa ccc
从上面的例子可以看出,首先向HashMap中添加<"aaa", "bbb">,接着添加<"aaa", "ccc">的时候由于与前面已经添加的数据有相同的key:"aaa",因此会用新的值"ccc"替换"bbb"。
但当用自定义的类的对象作为HashMap的key时,有时候会给人造成一种假象——key是可以重复的,示例如下:
import Java.util.*;
class Person{
String id;
String name;
public Person(String id, String name){
this.id=id;
this.name=name;
public String toString(){
return "id="+id+".name="+name;
}
}
public class Test{
public static void test2(){
System.out.println("Use String as key:");
HashMap<Person.String>hm=new HashMap<Person, String>();
Person p1=new Person("111", "name1");
Person p2=new Person("111", "name1");
hm.put(p1, "address1");
hm.put(p2, "address1");
Iterator iter=hm.entrySet().iterator();
while(iter.hasNext()){
Map.Entry entry=(Map.Entry)iter.next();
Person key=(Person)entry.getKey();
String val=(String)entry.getValue();
System.out.printin("key=" +key+" value="+val);
}
}
public static void main(String args[]){
test2();
}
}
程序运行结果为:
Use String as key:
key=id=111, name=name1 value=address1
key=id=111, name=name1 value=address1
从表面上看,向HashMap中添加的两个键值对的key值是相同的,可是为什么在后面添加的键值对没有覆盖前面的value呢?为了说明这个问题,下面首先介绍HashMap添加元素的操作过程。具体而言,在向HashMap中添加键值对<key,value>时,需要经过如下几个步骤:首先,调用key的hashCode()方法生成一个hash值h1,如果这个h1在HashMap中不存在,那么直接将<key,value>添加到HashMap中;如果这个h1已经存在,那么找出HashMap中所有hash值为h1的key,然后分别调用key的equals()方法判断当前添加的key值是否与已经存在的key值相同。如果equals()方法返回true,说明当前需要添加的key已经存在,那么HashMap会使用新的value值来覆盖掉旧的value值;如果equals()方法返回false,说明新增加的key在HashMap中不存在,因此会在HashMap中创建新的映射关系。当新增加的key的hash值已经在HashMap中存在时,就会产生冲突。一般而言,对于不同的key值可能会得到相同的hash值,因此就需要对冲突进行处理。一般而言,处理冲突的方法有开放地址法、再hash法、链地址法等。HashMap使用的是链地址法来解决冲突,具体操作方法如图所示。

May工作原理1

向HashMap中添加元素时,若有冲突产生,其实现方式如图所示。