zoukankan      html  css  js  c++  java
  • java集合类源码分析之Map(二)

    这一节主要讨论Map接口的几个实现类的区别和用法。

    1.线程安全

    Hashtable是线程安全的(原因与StringBuffer、Vector相似),而其他的Map实现类都是非线程安全的,至于为什么,可以看之前的一些文章,前面已经介绍地很详细了。

    这里特别讲解一下HashMap和Hashtable的区别与联系:

    • 继承的父类不同。Hashtable继承自Dictionary类,而HashMap继承自AbstractMap类。但二者都实现了Map接口。
    • 线程安全性不同。
    • key和value是否允许null值。 Hashtable中,key和value都不允许出现null值,HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。
    • 遍历的实现方式不同。Hashtable、HashMap都实现了 Iterator,而由于历史原因,Hashtable还使用Enumeration的方式 。
    • 哈希值不同。Hashtable直接使用对象的hashCode,而HashMap重新计算hash值。
    • 数组初始化和扩容方式不同。 Hashtable在不指定容量的情况下的默认容量为11,而HashMap为16,Hashtable不要求底层数组的容量一定要为2的整数次幂,而HashMap则要求一定为2的整数次幂。所以,Hashtable扩容时,将容量变为原来的2倍加1(2*old+1),而HashMap扩容时,将容量变为原来的2倍。

    2.适用条件

    HashMap:适用于需要快速查找的数据,并且数据无序的情况下,允许键为空(只一次),允许值为空;

    TreeMap:适用于按key有序存储的数据,不允许键为空;

    Hashtable:适用于有同步要求的情况下,保证线程安全,不允许键和值为空;

    LinkedHashMap:保存了元素插入时的顺序,具有HashMap的所有特性,但遍历时比HashMap要慢。

    HashMap与LinkedHashMap的比较示例:

     1     private static void linkedHashMapAnal() {
     2         //LinkedHashMap具有HashMap的所有特性,并且能够保留元素插入时的顺序
     3         Map<String, Integer> linkedHashMap = new LinkedHashMap<String, Integer>();
     4         Map<String, Integer> hashMap = new HashMap<String, Integer>();
     5         
     6         hashMap.put("A", 120);
     7         hashMap.put("B", 100);
     8         hashMap.put("C", 105);
     9         hashMap.put("D", 200);
    10         for(String key: hashMap.keySet()){
    11             System.out.print(key+":"+hashMap.get(key)+" ");
    12         }//D:200 A:120 B:100 C:105
    13         
    14         System.out.println();
    15         linkedHashMap.put("A", 120);
    16         linkedHashMap.put("B", 100);
    17         linkedHashMap.put("C", 105);
    18         linkedHashMap.put("D", 200);
    19         for(String key: linkedHashMap.keySet()){
    20             System.out.print(key+":"+linkedHashMap.get(key)+" ");
    21         }//A:120 B:100 C:105 D:200 
    22     }

    3.排序问题

    Map集合的排序常常分为按key排序和按value排序。

    • 按key排序

    有两种方式来实现Map的按key排序:TreeMap中的比较器和Collections类中的sort方法。

    1.TreeMap的按key排序

    1         //采用默认比较器按key值升序排列,进行存储
    2         Map<String, Integer> treeMap = new TreeMap<String, Integer>();
    3         treeMap.put("B", 120);
    4         treeMap.put("C", 105);
    5         treeMap.put("A", 100);
    6         for(String key: treeMap.keySet()){
    7             System.out.print(key+":"+treeMap.get(key)+", ");
    8         }    //A:100, B:120, C:105, 
    9     }
     1         //自定义比较器,实现降序存储
     2         Map<String, Integer> treeMap = new TreeMap<String, Integer>(new Comparator<String>() {
     3             @Override
     4             public int compare(String o1, String o2) {
     5 //                return 0; 默认升序
     6                 return o2.compareTo(o1); //降序
     7             }
     8         });
     9         treeMap.put("B", 120);
    10         treeMap.put("C", 105);
    11         treeMap.put("A", 100);
    12         for(String key: treeMap.keySet()){
    13             System.out.print(key+":"+treeMap.get(key)+", ");
    14         }    //C:105, B:120, A:100,
     1         //用SortedMap子集初始化TreeMap对象,调用参数自带的比较器
     2         //注意:TreeMap初始化的参数必须为SortedMap类型或者其实现类TreeMap类型,否则将调用默认比较器,所以此处也可以创建一个TreeMap类型的subMap
     3         SortedMap<String, Integer> subMap = new TreeMap<String, Integer>(new Comparator<String>() {
     4 
     5             @Override
     6             public int compare(String o1, String o2) {
     7                 // TODO Auto-generated method stub
     8                 return o2.compareTo(o1);
     9             }
    10         });
    11         subMap.put("B", 100);
    12         subMap.put("F", 120);
    13         subMap.put("D", 105);
    14         for(String key: subMap.keySet()){
    15             System.out.print(key+":"+subMap.get(key)+", ");
    16         }    //F:120, D:105, B:100, 
    17         
    18         System.out.println();
    19         
    20         Map<String, Integer> treeMap = new TreeMap<String, Integer>(subMap);
    21         for(String key: treeMap.keySet()){
    22             System.out.print(key+":"+treeMap.get(key)+", ");
    23         }    //F:120, D:105, B:100, 
    24         
    25         System.out.println();
    26         
    27         treeMap.put("A", 200);
    28         treeMap.put("C", 300);
    29         treeMap.put("E", 400);
    30         for(String key: treeMap.keySet()){
    31             System.out.print(key+":"+treeMap.get(key)+", ");
    32         }    //F:120, E:400, D:105, C:300, B:100, A:200, 

    2.HashMap的按key排序

     1         //用HashMap子集初始化TreeMap对象,调用默认比较器(升序)
     2          //注意:TreeMap初始化的参数为Map接口的实现类subMap
     3         Map<String, Integer> subMap = new HashMap<String, Integer>();
     4         subMap.put("B", 100);
     5         subMap.put("A", 120);
     6         subMap.put("C", 105);
     7         subMap.put("D", 200);
     8         for(String key: subMap.keySet()){
     9             System.out.print(key+":"+subMap.get(key)+", ");
    10         }    //D:200, A:120, B:100, C:105,
    11         
    12         System.out.println();
    13         
    14         Map<String, Integer> treeMap = new TreeMap<String, Integer>(subMap);        
    15         for(String key: treeMap.keySet()){
    16             System.out.print(key+":"+treeMap.get(key)+", ");
    17         }    //A:120, B:100, C:105, D:200,
     1         Map<String, Integer> hashMap = new HashMap<String, Integer>();
     2         
     3         //hashMap默认按key的哈希值排列,是一种无序存储
     4         hashMap.put("A", 100);
     5         hashMap.put("B", 120);
     6         hashMap.put("C", 105);
     7         hashMap.put("D", 100);
     8         for(String key: hashMap.keySet()){
     9             System.out.print(key+":"+hashMap.get(key)+" ");
    10         }//D:100 A:100 B:120 C:105   
    11         
    12         System.out.println();
    13         //将HashMap对象存储到List集合中
    14         ArrayList<Map.Entry<String, Integer>> mapList = new ArrayList<Map.Entry<String, Integer>>(hashMap.entrySet());
    15         //调用Collections的sort方法,并且重写比较器
    16         Collections.sort(mapList, new Comparator<Entry<String, Integer>>() {
    17 
    18             @Override
    19             public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
    20                 // TODO Auto-generated method stub
    21                 return o1.getKey().compareTo(o2.getKey());//升序,按value排序只需将getKey换成getValue即可
    22 //                return o2.getKey().compareTo(o1.getKey());//降序,按value排序只需将getKey换成getValue即可
    23             }
    24         } );
    25         
    26         for (int i = 0; i < mapList.size(); i++) {
    27             System.out.print(mapList.get(i).getKey()+":"+mapList.get(i).getValue()+" ");
    28         }//A:100 B:120 C:105 D:100 
    • 按value排序

    有了上面的例子,我们知道也可以通过Collections的sort方法来进行Map集合的value排序,包括HashMap和TreeMap。

     1         Map<String, Integer> hashMap = new HashMap<String, Integer>();
     2         
     3         hashMap.put("A", 100);
     4         hashMap.put("B", 120);
     5         hashMap.put("C", 105);
     6         hashMap.put("D", 110);
     7         for(String key: hashMap.keySet()){
     8             System.out.print(key+":"+hashMap.get(key)+" ");
     9         }//D:110 A:100 B:120 C:105    
    10         
    11         System.out.println();
    12         //将HashMap对象存储到List集合中
    13         ArrayList<Map.Entry<String, Integer>> mapList = new ArrayList<Map.Entry<String, Integer>>(hashMap.entrySet());
    14         //调用Collections的sort方法,并且重写比较器
    15         Collections.sort(mapList, new Comparator<Entry<String, Integer>>() {
    16 
    17             @Override
    18             public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
    19                 // TODO Auto-generated method stub
    20                 return o1.getValue().compareTo(o2.getValue());//升序
    21 //                return o2.getValue().compareTo(o1.getValue());//降序
    22             }
    23         } );
    24         
    25         for (int i = 0; i < mapList.size(); i++) {
    26             System.out.print(mapList.get(i).getKey()+":"+mapList.get(i).getValue()+" ");
    27         }//A:100 C:105 D:110 B:120 
     1         ArrayList<Map.Entry<String, Integer>> mapList = new ArrayList<Map.Entry<String, Integer>>(treeMap.entrySet());
     2         Collections.sort(mapList, new Comparator<Entry<String, Integer>>() {
     3 
     4             @Override
     5             public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
     6                 // TODO Auto-generated method stub
     7                 return o1.getValue().compareTo(o2.getValue());//升序
     8 //                return o2.getValue().compareTo(o1.getValue());//降序
     9             }
    10         });
    11         for (int i = 0; i < mapList.size(); i++) {
    12             System.out.print(mapList.get(i).getKey()+":"+mapList.get(i).getValue()+" ");
    13         }//B:100 D:105 F:120 C:300 E:400 A:500 
    14         
    15     }

     补充:如何实现HashMap按key降序排列?

    • 利用Collections类的sort方法实现:将HashMap存储到一个List中,然后调用Collections.sort()方法,同时重写比较器。
    • 利用TreeMap的putAll方法实现:创建一个空的TreeMap对象,同时初始化一个降序的比较器,用putAll方法将HashMap中的元素加入TreeMap对象中。
     1         Map<String, Integer> hashMap = new HashMap<String, Integer>();
     2         hashMap.put("A", 100);
     3         hashMap.put("B", 120);
     4         hashMap.put("C", 105);
     5         hashMap.put("F", 110);
     6         hashMap.put("E", 300);
     7         hashMap.put("D", 200);
     8         for(String key: hashMap.keySet()){
     9             System.out.print(key+":"+hashMap.get(key)+" ");
    10         }//D:200 E:300 F:110 A:100 B:120 C:105   
    11         
    12         System.out.println();
    13         
    14         //调用Collections的sort方法,实现HashMap按key降序排列
    15         ArrayList<Map.Entry<String, Integer>> mapList = new ArrayList<Map.Entry<String, Integer>>(hashMap.entrySet());
    16         Collections.sort(mapList, new Comparator<Entry<String, Integer >>() {
    17 
    18             @Override
    19             public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
    20                 // TODO Auto-generated method stub
    21                 return o2.getKey().compareTo(o1.getKey());//降序
    22             }
    23         });
    24         
    25         for (Iterator iterator = mapList.iterator(); iterator.hasNext();) {
    26             Entry<String, Integer> entry = (Entry<String, Integer>) iterator.next();
    27             System.out.print(entry.getKey()+":"+entry.getValue()+" ");
    28         }//F:110 E:300 D:200 C:105 B:120 A:100
    View Code
     1         Map<String, Integer> hashMap = new HashMap<String, Integer>();
     2         hashMap.put("A", 100);
     3         hashMap.put("B", 120);
     4         hashMap.put("C", 105);
     5         hashMap.put("F", 110);
     6         hashMap.put("E", 300);
     7         hashMap.put("D", 200);
     8         for(String key: hashMap.keySet()){
     9             System.out.print(key+":"+hashMap.get(key)+" ");
    10         }//D:200 E:300 F:110 A:100 B:120 C:105   
    11         
    12         System.out.println();
    13 
    14         //调用TreeMap的putAll方法,实现HashMap按key降序排列
    15         Map<String, Integer> treemap = new TreeMap<String, Integer>(new Comparator<String>() {
    16 
    17             @Override
    18             public int compare(String o1, String o2) {
    19                 // TODO Auto-generated method stub
    20                 return o2.compareTo(o1);//降序
    21             }
    22         });
    23         
    24         treemap.putAll(hashMap);
    25         for(String key: treemap.keySet()){
    26             System.out.print(key+":"+treemap.get(key)+" ");
    27         }//F:110 E:300 D:200 C:105 B:120 A:100 
    View Code

     至此,Map接口的实现类及其用法比较基本介绍完毕。

  • 相关阅读:
    jquery-追加元素
    mssql-异常value '0000-00-00' can not be represented as java.sql.Date
    lucene-Field.Store解析
    mysql-删除日志文件命令详解
    js-读取上传文件后缀
    js-处理回车事件
    maven-腾讯SDK(QQ)接口java引入pom配置
    ps制作gif图片
    java-commons-HttpClient超时设置setConnectionTimeout和setSoTimeout
    js-比较两个日期的大小
  • 原文地址:https://www.cnblogs.com/Wilange/p/7638329.html
Copyright © 2011-2022 走看看