Java 容器 & 泛型:五、HashMap 和 TreeMap的自白

一、Map回顾

    Map,又称映射表,是将键映射到值的对象。有四种实现Map接口并且经常使用的Map集合为:HashMap,TreeMap,Hashtable 和 LinkedHashMap.

泥瓦匠记忆宫殿:

    1、一个映射不包含重复的键

    2、每个键最多只能映射到一个值。

二、HashMap

    HashMap是基于哈希表的Map接口的实现。其对键进行散列,散列函数只能作用于键。下面模拟下,公司员工和找员工的例子:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

import java.util.HashMap;

import java.util.Map;

 

class Employee

{}

 

public class HaspMap01

{

    public static void main(String[] args)

    {

        Map<String, Employee> employees = new HashMap<String, Employee>();

        employees.put("1206010035", new Employee());

        System.out.println(employees);

         

        String number = "1206010035";

        System.out.println(employees.get(number));

    }

}

Run一下,大家可以见到结果:put方法,可以将键值映射添加进表。get方法则返回指定键所映射的值。从他们 hashCode 可以看出是同一个对象。

    HaspMap的键必须唯一,同样其同一个键不能存放两个值,如果对同一个键两次调用put方法,第二个值会取代第一个值。同样是允许使用 null 值和 null 键。下面泥瓦匠用一个简单的例子解释下:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

package javaBasic.collection.map;

 

import java.util.HashMap;

import java.util.Map;

 

 

public class HaspMap02

{

    @SuppressWarnings({ "unchecked", "rawtypes" })

    public static void main(String[] args)

    {

        Map map = new HashMap<String, String>();

        map.put(null, "null01");

        map.put(null, "null02");

        System.out.println(map);

        System.out.println(map.get(null));

    }

}

结果如下:

?


1

2

{null=null02}

null02

由此可见,第一个值被第二个值所替换了。

下面有三点是HashMap重要之处:

1、HashMap的构造函数

   HaspMap构造函数涉及两个参数:初始容量和加载因子。初试容量是哈希表创建时的其中桶的含量。加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。这两个参数都是影响HashMap的性能。默认构造一个具有默认初始容量 (16) 和默认加载因子 (0.75)。默认加载因子 (.75) 在时间和空间成本上是一种折衷的考虑。

2、和上次总结的Set都差不多,这个HashMap线程是不安全不同步的。如果想防止意外发生,则设置成同步即可:

?


1

Map m = Collections.synchronizedMap(new HashMap(...));

3、不同步的话,意味着存在快速失败导致的并发修改异常。

下面看一个复杂例子:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

package javaBasic.collection.map;

 

import java.util.HashMap;

import java.util.Map.Entry;

 

class A

{

    public boolean equals(Object obj)

    {

        return true;

    }

}

 

class B

{

    public int hashCode()

    {

        return 1;

    }

}

 

class C

{

    public int hashCode()

    {

        return 2;

    }

 

    public boolean equals(Object obj)

    {

        return true;

    }

}

 

public class HashMap03

{

    public static void main(String[] args)

    {

        HashMap<A, Integer> hashMapA = new HashMap<A, Integer>();

        hashMapA.put(new A(), 10);

        hashMapA.put(new A(), 5);

         

        System.out.println("HashMapA Elements:");

        System.out.print("\t" + hashMapA + "\n");

         

        // loop HashMapA

        for(Entry<A, Integer> entryA : hashMapA.entrySet())

        {

            System.out.println(entryA.getKey().toString()+"-"+entryA.getValue());

        }

         

        HashMap<B, Integer> hashMapB = new HashMap<B, Integer>();

        hashMapB.put(new B(), 10);

        hashMapB.put(new B(), 5);

         

        System.out.println("HashMapB Elements:");

        System.out.print("\t" + hashMapB + "\n");

         

        // loop HashMapB

        for(Entry<B, Integer> entryB : hashMapB.entrySet())

        {

            System.out.println(entryB.getKey().toString()+"-"+entryB.getValue());

        }

         

        HashMap<C, Integer> hashMapC = new HashMap<C, Integer>();

        hashMapC.put(new C(), 10);

        hashMapC.put(new C(), 5);

         

        System.out.println("HashMapC Elements:");

        System.out.print("\t" + hashMapC + "\n");

         

        // loop HashMap

        for(Entry<C, Integer> entryC : hashMapC.entrySet())

        {

            System.out.println(entryC.getKey().toString()+"-"+entryC.getValue());

        }

    }

}

运行一下,可以看到以下结果:

由此可见,其中和 Java 容器 & 泛型:三、HashSet,TreeSet 和 LinkedHashSet比较 中涉及的知识点一致:

集合判断两个元素相等不单单是equals方法,并且必须hashCode()方法返回值也要相等。

三、TreeMap

    TreeMap使用树结构实现(红黑树),集合中的元素进行排序,但是添加、删除和包含的算法复杂度为O(log(n))。其实Map特性基本都是一致的,比如看下面的简单例子:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

public class TreeMap01

{  

    @SuppressWarnings({ "rawtypes", "unchecked" })

    public static void main(String[] args)

    {

        Map map = new TreeMap();

        map.put("1", "1");

        map.put("4", "4");

        map.put("2", "2");

        map.put("2", "3");

        System.out.println(map);

    }

}

结果如下:

?


1

{1=1, 2=3, 4=4}

从中我们可以看出

1、TreeMap实现了SortedMap,顾名思义,其表示为有排序的集合。

2、同样其同一个键不能存放两个值,如果对同一个键两次调用put方法,第二个值会取代第一个值。

四、总结

HashMap与TreeMap
      1、HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。HashMap中元素的排列顺序是不固定的)。
      2、  HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。集合框架”提供两种常规的Map实现:HashMap和TreeMap (TreeMap实现SortedMap接口)。
      3、在Map 中插入、删除和定位元素,HashMap 是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。使用HashMap要求添加的键类明确定义了hashCode()和 equals()的实现。 这个TreeMap没有调优选项,因为该树总处于平衡状态。
时间: 2024-11-03 22:18:21

Java 容器 & 泛型:五、HashMap 和 TreeMap的自白的相关文章

Java 容器 &amp; 泛型:一、认识容器

容器是Java语言学习中重要的一部分.泥瓦匠我的感觉是刚开始挺难学的,但等你熟悉它,接触多了,也就"顺理成章"地知道了.Java的容器类主要由两个接口派生而出:Collection和Map.   一.Collection vs Collections 首先,Collection 和 Collections 是两个不同的概念.之所以放在一起,是为了更好的比较.Collection是容器层次结构中根接口.而Collections是一个提供一些处理容器类静态方法的类. JDK不提供Colle

Java 容器 &amp; 泛型:三、HashSet,TreeSet 和 LinkedHashSet比较

上一篇总结了下ArrayList .LinkedList和Vector比较,今天泥瓦匠总结下Hash .LinkedList和Vector比较.其实大家都是Collection,只不过有点各自特性.那就是数据结构的不同表现.   一.Set回顾 一个不包括重复元素(包括可变对象)的Collection,是一种无序的集合.Set不包含满 a.equals(b) 的元素对a和b,并且最多有一个null. 泥瓦匠的记忆宫殿: 1.不允许包含相同元素 2.判断对象是否相同,根据equals方法   二.

Java 容器 &amp; 泛型:二、ArrayList 、LinkedList和Vector比较

一.List回顾 序列(List),有序的Collection,正如它的名字一样,是一个有序的元素列表.确切的讲,列表通常允许满足 e1.equals(e2) 的元素对 e1 和 e2,并且如果列表本身允许 null 元素的话,通常它们允许多个 null 元素.实现List的有:ArrayList.LinkedList.Vector.Stack等.值得一提的是,Vector在JDK1.1的时候就有了,而List在JDK1.2的时候出现,待会我们会聊到ArrayList和Vector的区别.  

Java 容器 &amp; 泛型:四、Colletions.sort 和 Arrays.sort 的算法

一.Colletions和Arrays Collentions 此类完全是服务容器的"包装器".提供了一些操作或者返回容器的静态方法.而Arrays是用来操作数组的各种方法.其中它们的联系在于其中的Sort方法,也就是这次博客的主题.   二.插入,快速.归并基本算法 ① 插入排序 {a1},{a2,a3,a4,-,an}} {{a1⑴,a2⑴},{a3⑴,a4⑴ -,an⑴}} - {{a1(n-1),a2(n-1) ,-},{an(n-1)}} 原理及记忆方法:每次处理就是将无序数

Java 容器 &amp; 泛型:六、容器讲到为什么要使用泛型

ArrayList是集合类中无处不在的,泛型也是,泛型对集合类尤其有用.但是为啥要使用泛型?理解好了这个问题可以帮助理解相关的更多知识点.下面泥瓦匠以最简单的例子来验证这个问题. 一.泛型 泛型的目的是为了可以让更多不同类型的对象重用.没错,这样理解就太low.真正目的是为了在编译时找到bug,而不是在运行时.(编译时,指的是源代码翻译成机器识别的代码的时候.运行时,是指代码在机器中运行的时候.)泛型只存在编译时,理解这个可以帮助你更好的理解泛型. 这样,在编译时会比在运行时更容易地找到bug和

在容器中使用Java RAM:五种不丢失内存的方法

本文讲的是在容器中使用Java RAM:五种不丢失内存的方法[编者的话]在这篇文章中,我们想分享一些看起来不那么明显的关于在容器内部中Java内存管理和弹性扩展的细节. 您将看到在即将发布的JDK版本中需要注意的问题和重要更新的列表,以及核心难点的现有解决方法. 我们收集了可以提高Java应用程序的资源使用效率的五个最有趣和最有用的问题点. [3 天烧脑式 Docker 训练营 | 上海站]随着Docker技术被越来越多的人所认可,其应用的范围也越来越广泛.本次培训我们理论结合实践,从Docke

Java 集合系列14之 Map总结(HashMap, Hashtable, TreeMap, WeakHashMap等使用场景)

概要 学完了Map的全部内容,我们再回头开开Map的框架图.   本章内容包括:第1部分 Map概括第2部分 HashMap和Hashtable异同第3部分 HashMap和WeakHashMap异同 转载请注明出处:http://www.cnblogs.com/skywang12345/admin/EditPosts.aspx?postid=3311126   第1部分 Map概括 (01) Map 是"键值对"映射的抽象接口.(02) AbstractMap 实现了Map中的绝大部

java容器 collection-JAVA中什么是容器?什么是集合?求大神指导

问题描述 JAVA中什么是容器?什么是集合?求大神指导 容器是什么?跟接口是什么关系?集合又是什么?求大神帮忙?????? 解决方案 Java集合容器主要有以下几类: 1,内置容器:数组 2,list容器:Vetor,Stack,ArrayList,LinkedList, CopyOnWriteArrayList(1.5),AttributeList(1.5),RoleList(1.5),RoleUnresolvedList(1.5), ConcurrentLinkedQueue(1.5),Ar

Java容器——未获支持的操作

    先看一个例子: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import