`
Angelialily
  • 浏览: 242436 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

教大家如何更好的使用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的源码里能够读出来的信息,有兴趣的可以自己去看看源码。

1
2
分享到:
评论

相关推荐

    Java中HashMap详解(通俗易懂).doc

    1. **哈希函数**:HashMap使用键对象的hashCode()方法生成哈希码,这个哈希码用于确定元素在内部数组中的位置。哈希函数的目标是尽可能地将不同的键映射到不同的桶,以减少冲突。 2. **哈希冲突解决**:尽管哈希...

    HashMap CRUD操作

    通过这个例子,初学者可以更好地理解HashMap的基本操作以及在实际问题中的应用。同时,了解并掌握HashMap的这些基本操作对于Java开发者来说是非常重要的,因为它们在各种场景下都有广泛的应用。

    Java 实例 - HashMap遍历源代码-详细教程.zip

    这个实例教程将深入解析HashMap的遍历方法及其源代码,帮助开发者更好地理解和使用HashMap。以下是对这个主题的详细讲解: 1. **HashMap概述**: HashMap是一个基于哈希表实现的键值对数据结构,提供了快速的存取...

    Hash Map for geeks_hashmap_Geeks_源码

    标题中的“Hash Map for geeks_hashmap_Geeks_源码”...综上所述,这个“Hash Map for geeks_hashmap_Geeks_源码”资源很可能会涵盖以上所有内容,并可能通过具体示例和深入解析,帮助开发者更好地理解和应用HashMap。

    JAVA实用教程 高等学校专用课本

    最后,为了帮助读者更好地理解和应用所学知识,本教程的电子教案《Java大学实用教程》中通常会包含丰富的实例代码、习题解答和项目案例。通过这些资料,学习者可以进行实践操作,提升编程技能。 总之,《JAVA实用...

    java2实验教程第6版实验指导书

    《Java2实验教程第6版实验指导书》是学习Java编程的重要参考资料,尤其对于初学者而言,它提供了丰富的实践案例和详细的步骤指南。...在学习过程中,应结合代码示例进行实践,以便更好地理解和掌握Java语言的精髓。

    Java2 实用教程第4版 课件

    这些课件提供了丰富的示例代码和练习,帮助学习者巩固所学,更好地理解和应用Java语言。 总之,《Java2实用教程第4版》课件是一份全面而系统的Java学习资源,无论是对于初次接触Java的初学者,还是希望提升Java技能...

    最好的java教程,英文版的。官方java tutorial

    Oracle官方提供的Java Tutorial是学习Java的绝佳资源,它涵盖了Java语言的各个方面,从基础知识到高级特性的深入探讨,旨在帮助初学者和有经验的开发者更好地理解和运用Java。 这个教程以英文版的形式提供,虽然...

    JAVA教程(原上课用PPT版)

    这个"JAVA教程(原上课用PPT版)"提供了一种直观、结构化的学习方式,使得理论与实践相结合,帮助学习者更好地掌握Java的核心概念。 Java是一种广泛应用于企业级应用、移动开发(如Android)、大数据处理、云计算等...

    Java程序设计入门教程(PDF),很好教程,希望对大家有用.

    容器和集合框架是Java的核心部分,包括ArrayList、LinkedList、HashSet、HashMap等。它们提供了存储和操作数据的结构和算法,是实现数据结构和算法的基础。 最后,Java SE(标准版)和Java EE(企业版)的区别也...

    java教程

    Java教程是针对编程初学者和经验丰富的开发者们提供的宝贵资源,尤其对于想要深入理解...在学习过程中,结合实际编写代码和解决具体问题,将有助于更好地理解和吸收所学内容,为成为一个合格的Java程序员打下坚实基础。

    java学习清华大学教程

    清华大学的教程通常以理论与实践相结合的方式展开,强调实际操作和案例分析,以帮助学生更好地理解和掌握知识。尽管难度可能相对较高,但通过深入学习和不断实践,你将能够系统地掌握Java编程,为未来的软件开发打下...

    JAVA教程(实用教程)

    此教程基于“java2实用教程(第3版)”进行讲解,涵盖了Java语言的基础到进阶内容,通过丰富的课件形式帮助学习者更好地理解和掌握Java编程。 课程内容可能包括以下几个方面: 1. **Java基础**:首先,会介绍Java...

    Java高级实用教程

    Java高级实用教程主要涵盖的是Java编程语言进阶的知识点,这些内容对于想要深入理解Java特性和提高编程技能的开发者至关重要。...通过阅读和实践教程中的内容,开发者可以更好地理解和掌握Java的强大功能。

    Java2 实用教程

    14. **模块化系统**:Java 9引入了模块化系统,通过模块化设计可以更好地组织和打包大型项目,提高程序的可维护性和性能。 在《Java2 实用教程》中,每个主题都会有详尽的解释、示例代码和实践练习,帮助读者深入...

    java2使用教程第三版课件

    Java 2 使用教程第三版是针对Java编程语言的深度学习资料,特别适合自学者使用。这份教程由大连交通大学编著,旨在帮助初学者和有一定...在学习过程中,结合实际项目实践,将使理论与应用相结合,更好地掌握Java编程。

    java清华大学教程

    教程的亮点在于其生动的动画演示,这种多媒体教学方式使得抽象的编程概念变得更为直观,有助于学习者更好地理解和记忆。同时,教程采用HTML格式,这种易于阅读和导航的文本格式使得学习过程更为便捷,可以随时查阅和...

    Java入门级教程

    Java入门级教程是一个针对初学者精心设计的在线学习资源,旨在帮助那些对编程感兴趣的人们快速...在学习过程中,记得理论与实践相结合,不断编写代码,解决实际问题,这样才能更好地理解和掌握Java这门强大的编程语言。

    JAVA基础教程,给大家更多可以参考

    本教程“JAVA基础教程”是为初学者设计的,旨在提供全面的Java学习资源,帮助大家更好地理解和掌握Java编程的核心概念。 在Java私塾跟我学系列中,我们将涵盖以下几个主要的知识点: 1. **Java环境配置**:首先,...

    java教程下载

    【标题】:“Java教程下载”通常指的是获取学习Java...同时,结合其他在线资源和实践项目,可以更好地巩固和提升技能。在学习过程中,遇到问题应积极查阅文档、参与论坛讨论,不断实践和总结,才能真正掌握Java编程。

Global site tag (gtag.js) - Google Analytics