教大家如何更好的使用HashMap


先来看一个例子:
将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的源码里能够读出来的信息,有兴趣的可以自己去看看源码。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值