`

HashMap 和TreeMap

    博客分类:
  • Java
阅读更多

本文重点介绍HashMap。首先介绍一下什么是Map。在数组中我们是通过数组下标来对其内容索引的,而在Map中我们通过对象来对对象进行索引,用来索引的对象叫做key,其对应的对象叫做value。在下文中会有例子具体说明。

再来看看HashMap和TreeMap有什么区别。HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。

import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Hashtable;
import java.util.TreeMap;
class  HashMaps
{
       public static void main(String[] args)
      {
            Map map=new HashMap();           
            map.put("a", "aaa");
            map.put("b", "bbb");
            map.put("c", "ccc");
            map.put("d", "ddd");
          
            Iterator iterator = map.keySet().iterator();           
            while (iterator.hasNext()) {
             Object key = iterator.next();
             System.out.println("map.get(key) is :"+map.get(key));
            }      
           
           
           
            Hashtable tab=new Hashtable();           
            tab.put("a", "aaa");
            tab.put("b", "bbb");
            tab.put("c", "ccc");
            tab.put("d", "ddd");
            Iterator iterator_1 = tab.keySet().iterator();
            while (iterator_1.hasNext()) {
             Object key = iterator_1.next();
             System.out.println("tab.get(key) is :"+tab.get(key));
            }        
           
            TreeMap tmp=new TreeMap();           
            tmp.put("a", "aaa");
            tmp.put("b", "bbb");
            tmp.put("c", "ccc");
            tmp.put("d", "ddd");
            Iterator iterator_2 = tmp.keySet().iterator();
            while (iterator_2.hasNext()) {
             Object key = iterator_2.next();
             System.out.println("tmp.get(key) is :"+tmp.get(key));
            }        
                     
        
       }
    
}
执行完后,果然是这样的(hashmap是没有顺序的,而treemap则是按顺序排列的哦!!)

 

下面就要进入本文的主题了。先举个例子说明一下怎样使用HashMap:

import java.util.*;

public class Exp1 {
     public static void main(String[] args){
          HashMap h1=new HashMap();
          Random r1=new Random();    
          for (int i=0;i<1000;i++){
               Integer t=new Integer(r1.nextInt(20));
               if (h1.containsKey(t))
                    ((Ctime)h1.get(t)).count++;
               else
                    h1.put(t, new Ctime());
          }
          System.out.println(h1);
     }
}

class Ctime{
     int count=1;
     public String toString(){
          return Integer.toString(count);
     }
}

在HashMap中通过get()来获取value,通过put()来插入value,ContainsKey()则用来检验对象是否已经存在。可以看出,和ArrayList的操作相比,HashMap除了通过key索引其内容之外,别的方面差异并不大。

 

前面介绍了,HashMap是基于HashCode的,在所有对象的超类Object中有一个HashCode()方法,但是它和equals方法一样,并不能适用于所有的情况,这样我们就需要重写自己的HashCode()方法。下面就举这样一个例子:

import java.util.*;

public class Exp2 {
     public static void main(String[] args){
          HashMap h2=new HashMap();
          for (int i=0;i<10;i++)
               h2.put(new Element(i), new Figureout());
          System.out.println("h2:");
          System.out.println("Get the result for Element:");
          Element test=new Element(5);
          if (h2.containsKey(test))
               System.out.println((Figureout)h2.get(test));
          else
               System.out.println("Not found");
     }
}

class Element{
     int number;
     public Element(int n){
          number=n;
     }
}

class Figureout{
     Random r=new Random();
     boolean possible=r.nextDouble()>0.5;
     public String toString(){
          if (possible)
               return "OK!";
          else
               return "Impossible!";
     }
}

 

在这个例子中,Element用来索引对象Figureout,也即Element为key,Figureout为value。在Figureout中随机生成一个浮点数,如果它比0.5大,打印"OK!",否则打印"Impossible!"。之后查看Element(3)对应的Figureout结果如何。

结果却发现,无论你运行多少次,得到的结果都是"Not found"。也就是说索引Element(3)并不在HashMap中。这怎么可能呢?

原因得慢慢来说:Element的HashCode方法继承自Object,而Object中的HashCode方法返回的HashCode对应于当前的地址,也就是说对于不同的对象,即使它们的内容完全相同,用HashCode()返回的值也会不同。这样实际上违背了我们的意图。因为我们在使用 HashMap时,希望利用相同内容的对象索引得到相同的目标对象,这就需要HashCode()在此时能够返回相同的值。在上面的例子中,我们期望 new Element(i) (i=5)与 Element test=new Element(5)是相同的,而实际上这是两个不同的对象,尽管它们的内容相同,但它们在内存中的地址不同。因此很自然的,上面的程序得不到我们设想的结果。下面对Element类更改如下:

class Element{
     int number;
     public Element(int n){
          number=n;
     }
     public int hashCode(){
          return number;
     }
     public boolean equals(Object o){
          return (o instanceof Element) && (number==((Element)o).number);
     }
}

在这里Element覆盖了Object中的hashCode()和equals()方法。覆盖hashCode()使其以number的值作为 hashcode返回,这样对于相同内容的对象来说它们的hashcode也就相同了。而覆盖equals()是为了在HashMap判断两个key是否相等时使结果有意义(有关重写equals()的内容可以参考我的另一篇文章《重新编写Object类中的方法 》)。修改后的程序运行结果如下:

h2:
Get the result for Element:
Impossible!

请记住:如果你想有效的使用HashMap,你就必须重写在其的HashCode()。

还有两条重写HashCode()的原则:

  1. 不必对每个不同的对象都产生一个唯一的hashcode,只要你的HashCode方法使get()能够得到put()放进去的内容就可以了。即"不为一原则"。
  2. 生成hashcode的算法尽量使hashcode的值分散一些,不要很多hashcode都集中在一个范围内,这样有利于提高HashMap的性能。即"分散原则"。

至于第二条原则的具体原因,有兴趣者可以参考Bruce Eckel的《Thinking in Java》,在那里有对HashMap内部实现原理的介绍,这里就不赘述了。

掌握了这两条原则,你就能够用好HashMap编写自己的程序了。不知道大家注意没有,java.lang.Object中提供的三个方法:clone (),equals()和hashCode()虽然很典型,但在很多情况下都不能够适用,它们只是简单的由对象的地址得出结果。这就需要我们在自己的程序中重写它们,其实java类库中也重写了千千万万个这样的方法。利用面向对象的多态性——覆盖,Java的设计者很优雅的构建了Java的结构,也更加体现了Java是一门纯OOP语言的特性

分享到:
评论

相关推荐

    Java中HashMap和TreeMap的区别深入理解

    HashMap和TreeMap是Java中两种常用的Map实现,它们各自具有不同的特性和使用场景。 HashMap是基于哈希表实现的,其核心思想是通过键对象的hashCode()方法来快速定位到对应的桶(bucket),从而提高查找效率。...

    在Java中如何决定使用 HashMap 还是 TreeMap

    Java 中的 HashMap 和 TreeMap 选择指南 在 Java 中,HashMap 和 TreeMap 都是常用的 Map 实现类,但是在实际开发中,选择哪种 Map 实现类往往让人感到迷茫。下面我们将详细介绍 HashMap 和 TreeMap 的特点、优缺点...

    Java里多个Map的性能比较(TreeMap、HashMap、ConcurrentSkipListMap)

    在Java编程中,Map接口是用于存储键值对的数据结构,而Java提供了多种Map的实现,包括TreeMap、HashMap和ConcurrentSkipListMap。本文主要比较了这三种Map的性能,尤其是在插入和查找操作上的效率。 1. **TreeMap**...

    java中HashMap,LinkedHashMap,TreeMap,HashTable的区别

    - **性能**:尽管`TreeMap`提供排序功能,但它的时间复杂度通常是O(log n),因此在某些情况下可能比`HashMap`和`LinkedHashMap`慢。 #### 4. HashTable `HashTable`是一种古老的`Map`实现,它的设计是为了确保线程...

    Map,HashMap,TreeMap的使用

    在 Java 中,HashMap、LinkedHashMap、TreeMap 都实现了 Map 接口,都是 Map 的子类,每个子类都有其特点和使用场景。 HashMap HashMap 是最常用的 Map 实现类,它根据键的哈希码值存储数据,能够快速地存储和获取...

    第9讲 对比Hashtable、HashMap、TreeMap有什么不同?1

    HashMap、Hashtable和TreeMap都是Java中实现Map接口的类,它们用于存储键值对数据,但各自具有不同的特点和使用场景。 HashMap是最常用的Map实现,它通过哈希表(散列表)实现,提供快速的插入、查找和删除操作,...

    java HashMap,TreeMap与LinkedHashMap的详解

    在Java编程语言中,`HashMap`、`TreeMap`和`LinkedHashMap`都是`java.util.Map`接口的实现,它们提供了不同的数据存储和访问策略。本文将深入探讨这三种数据结构的特点、工作原理以及适用场景。 1. **HashMap** `...

    treemap treeset hashset hashmap 简要介绍

    在Java编程语言中,集合框架提供了多种数据结构来存储和操作数据,其中`TreeMap`、`TreeSet`、`HashSet`以及`HashMap`是最常用的数据结构之一。这些集合类各自有着独特的特性和应用场景,下面将对它们进行详细介绍。...

    浅谈Java中HashMap类的使用.pdf

    HashMap 和 TreeMap 都是 Java 语言中的 Map 接口实现,但它们有所不同。HashMap 不保证映射的顺序,而 TreeMap 则保证映射的顺序。当需要顺序输出时,可以使用 TreeMap 类实现 Map 集合。 六、实例应用 例如,在...

    11.集合框架001-Collection接口21-23

    描述中提到的“21-23”可能是指三个视频教程的章节,分别深入分析了HashMap的源码、HashMap的内部结构总结和TreeMap。 首先,Collection接口是Java集合框架的根接口,它定义了对一组对象进行操作的基本方法,如添加...

    java-hashmaptreemap的算法实现和应用

    在Java编程语言中,`HashMap`和`TreeMap`是两种常见的`Map`接口实现,它们各自具有不同的特性和用途。这两个数据结构都是用来存储键值对的数据结构,但它们的内部实现机制和性能特点有所不同。 HashMap是基于哈希表...

    java集合使用实例

    本资源聚焦于Java集合中的四个关键类:HashSet、TreeSet、HashMap和TreeMap,它们分别代表了不同类型的集合容器。 1. **HashSet**:HashSet是一个不允许重复元素的无序集合。它基于哈希表实现,插入和查找操作的...

    金陵科技学院软件院大二上Java高级1212Map.docx

    本教程将详细介绍如何使用Map以及特定实现如HashMap和TreeMap。 1. **定义Map并加入数据**: 在Java中,我们通常通过创建HashMap或TreeMap的实例来创建Map。例如,以下代码展示了如何创建一个HashMap,并插入一些...

    java集合类学习汇总

    Map接口存储键值对,如HashMap、TreeMap和LinkedHashMap,HashMap快速查找,TreeMap按键排序,LinkedHashMap保持插入顺序或访问顺序。 接下来,我们来看一些具体的应用场景。ArrayList常用于需要快速随机访问且不...

    Java 集合方面的面试题

    HashMap 和 TreeMap 有什么区别? 什么是迭代器?如何使用它来遍历集合? 什么是 fail-fast 机制? 如何使用 Collections 类对集合进行排序? 什么是 Comparable 和 Comparator 接口?它们有什么区别? 如何使用 ...

    java基础之集合面试题共4页.pdf.zip

    3. **HashMap和TreeMap**:HashMap提供快速的key-value存取,不保证元素顺序,适合于不需要排序且性能优先的情况。TreeMap内部维护了一个红黑树,元素按照键的自然排序或者自定义比较器排序,查找、插入和删除的时间...

    Java集合讲义大全.docx

    常见的 Map 实现类有 HashMap 和 TreeMap。 2. Collection 和 Iterator Collection 是 List 和 Set 的父接口,在 Collection 中定义了一些主要方法,例如 add、addAll、clear、contains、containsAll、equals、...

    Java 72道面试题和答案.docx

    HashMap和TreeMap分别基于哈希表和红黑树,而Hashtable是线程安全的HashMap。 使用集合框架的优点包括: - 容量自增长:集合可以自动扩展其大小以适应更多的元素。 - 高性能的数据结构和算法:集合框架内置了高效的...

Global site tag (gtag.js) - Google Analytics