先来看一个例子:
将Student作为key HomeInfo作为value放入HashMap容器中
然后看打印的结果
package com.xkd;
public class Student {
private String name;
private int age;
private String ic;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getIc() {
return ic;
}
public void setIc(String ic) {
this.ic = ic;
}
@Override
public String toString()
{
return "[name:"+getName()+" age:"+getAge()+" ic:"+getIc()+"]";
}
}
package com.xkd;
public class HomeInfo {
private String fatherName;
private String motherName;
private String address;
public String getFatherName() {
return fatherName;
}
public void setFatherName(String fatherName) {
this.fatherName = fatherName;
}
public String getMotherName() {
return motherName;
}
public void setMotherName(String motherName) {
this.motherName = motherName;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString()
{
return "[father:"+getFatherName()+" mother:"+getMotherName()+" address:"+getAddress()+"]";
}
}
package com.xkd;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class HashMapTest {
/**
* @param args
*/
public static void main(String[] args) {
Map<Student,HomeInfo> map = new HashMap<Student,HomeInfo>();
//
Student st1 = new Student();
st1.setName("张三");
st1.setAge(19);
st1.setIc("356721198906250043");
HomeInfo hi1 = new HomeInfo();
hi1.setFatherName("张天保");
hi1.setMotherName("黄小英");
hi1.setAddress("河北保定");
//
Student st2 = new Student();
st2.setName("赵六");
st2.setAge(18);
st2.setIc("356721199006250047");
HomeInfo hi2 = new HomeInfo();
hi2.setFatherName("赵大雄");
hi2.setMotherName("刘梅");
hi2.setAddress("湖南长沙");
//
Student st3 = new Student();
st3.setName("张三");
st3.setAge(19);
st3.setIc("356721198906250043");
HomeInfo hi3 = new HomeInfo();
hi3.setFatherName("张天保");
hi3.setMotherName("黄小英");
hi3.setAddress("河北保定");
map.put(st1, hi1);
map.put(st2, hi2);
map.put(st3, hi3);
for(Entry<Student, HomeInfo> ensh : map.entrySet())
{
System.out.println("---------------------------------------------------------------------------");
System.out.println("----key: "+ensh.getKey());
System.out.println("----value: "+ensh.getValue());
}
}
}
打印结果:
---------------------------------------------------------------------------
----key: [name:张三 age:19 ic:356721198906250043]
----value: [father:张天保 mother:黄小英 address:河北保定]
---------------------------------------------------------------------------
----key: [name:赵六 age:18 ic:356721199006250047]
----value: [father:赵大雄 mother:刘梅 address:湖南长沙]
---------------------------------------------------------------------------
----key: [name:张三 age:19 ic:356721198906250043]
----value: [father:张天保 mother:黄小英 address:河北保定]
很显然打印的结果出乎了我们的预料,第一个和第三个重了,按道理来讲HashMap是不能放入重复key这里
为什么没有去掉呢,原因很简单 st1,st2,st3 是new 出来的对象,他们自然是!=的关系。打印上面的结果
也就在情理之中了。
现在问题来了,如果我要想让他们不重复出现,也就是当student信息相同时则认为是同一个人,那又应该怎么办呢
先来看如何解决,再来看为什么
在Student类中 加入如下代码
@Override
public int hashCode() {
return this.age;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Student)
{
Student s = (Student)obj;
if(this == s)
{
return true;
}
else if(this.name.equals(s.getName()) && this.age ==s.getAge() && this.ic.equals(s.getIc()))
{
return true;
}
}
return false;
}
再次运行结果:
---------------------------------------------------------------------------
----key: [name:张三 age:19 ic:356721198906250043]
----value: [father:张天保 mother:黄小英 address:河北保定]
---------------------------------------------------------------------------
----key: [name:赵六 age:18 ic:356721199006250047]
----value: [father:赵大雄 mother:刘梅 address:湖南长沙]
是不是达到想要的结果了。
两个方法的含义我就不再说了。
这里要注意的是,必须两个方法同时复写才有效,并且,hashCode()方法中不要返回 super.hashCode(),否则达不到
你想要的效果。为什么会这样???这跟HashMap的存储结构有关,在HashMap中是用一个数组来存放元素,其中每一
个下标值内的元素都是一个<key,value>结构的链表,大家可以在脑子里构想一下这个结构,应该就很清楚了,在每往HashMap中
存放一个值的时候,首先会根据hashCode的值来判断该把这个值放在哪一下标去,然后再遍历这个下标里的链表,看是否有与
当前key重复的元素,判断的条件为 对象是否== 或者 equals()是否为真 大家在这应该明白为什么会重写equals()方法了吧
在取值的时候也是一样,先根据Hash值判断如果有这个对象它应该被存在了哪一个下标里,然后再遍历这个下标里的链表。
(有兴趣的可以看一下,Object类中的equals()方法,它直接返回 this==要比较的对象)
下面有个有趣的现象
System.out.println("=============================end1========================================");
//***
st1.setAge(20);
for(Entry<Student, HomeInfo> ensh : map.entrySet())
{
System.out.println("---------------------------------------------------------------------------");
System.out.println("----key: "+ensh.getKey());
System.out.println("----value: "+ensh.getValue());
}
System.out.println("=============================end2========================================");
//
Set<Student> set = map.keySet();
for(Student s : set)
{
System.out.println("---------------------------------------------------------------------------");
System.out.println("----key: "+s);
System.out.println("----value: "+map.get(s));
}
打印结果:
=============================end1========================================
---------------------------------------------------------------------------
----key: [name:张三 age:20 ic:356721198906250043]
----value: [father:张天保 mother:黄小英 address:河北保定]
---------------------------------------------------------------------------
----key: [name:赵六 age:18 ic:356721199006250047]
----value: [father:赵大雄 mother:刘梅 address:湖南长沙]
=============================end2========================================
---------------------------------------------------------------------------
----key: [name:张三 age:20 ic:356721198906250043]
----value: null
---------------------------------------------------------------------------
----key: [name:赵六 age:18 ic:356721199006250047]
----value: [father:赵大雄 mother:刘梅 address:湖南长沙]
很奇怪吧! 第一次打印了张三家的信息 而第二次则没有找到。出现这种现象都是因为这句话st1.setAge(20)
为什么? 回想在取值的时候是怎么操作的 先根据Hash值判断如果有该对象它应该被放在哪一个下标里面,而我们的Hash值刚好又
与我们的age有关 这样一来,改age相当于改变了Hash值,结果可想而知。所以在我们在使用Hash容器要注意,key,value放到容器
后千万不可以修改与hashCode()相关的属性,否则容易造成数据丢失。
当然,在我们用基础类包括String作为key的时候完全可以不用考虑这些,为什么,大家自己去想吧。
现在大家可以自己总结一下,使用HashMap时应该注意哪些,不应该做哪些不能做的操作。
这些都是从JDK的源码里能够读出来的信息,有兴趣的可以自己去看看源码。