zoukankan      html  css  js  c++  java
  • Java 容器 & 泛型:五、HashMap 和 TreeMap的自白

    Writer:BYSocket(泥沙砖瓦浆木匠)

    微博:BYSocket

    豆瓣:BYSocket

    Java 容器的文章这次应该是最后一篇了:Java 容器 系列。 今天泥瓦匠聊下 Maps。

    一、Map回顾

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

    泥瓦匠记忆宫殿:

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

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

    MapClassHierarchy-600x354

    二、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(" " + hashMapA + " ");
             
            // 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(" " + hashMapB + " ");
             
            // 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(" " + hashMapC + " ");
             
            // 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没有调优选项,因为该树总处于平衡状态。

    Writer:BYSocket(泥沙砖瓦浆木匠)

    微博:BYSocket

    豆瓣:BYSocket

  • 相关阅读:
    Best Time to Buy and Sell Stock III
    Valid Palindrome
    Longest Substring Without Repeating Characters
    Copy List with Random Pointer
    Add Two Numbers
    Recover Binary Search Tree
    Anagrams
    ZigZag Conversion
    Merge k Sorted Lists
    Distinct Subsequences
  • 原文地址:https://www.cnblogs.com/Alandre/p/4478815.html
Copyright © 2011-2022 走看看