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接口的实现类及其用法比较基本介绍完毕。

 

posted @   Wilange  阅读(537)  评论(2编辑  收藏  举报
编辑推荐:
· 如何做好技术经理
· Kafka 的“无锁哲学”:高效消息流动的背后
· 时间轮在 Netty , Kafka 中的设计与实现
· MySQL 优化利器 SHOW PROFILE 的实现原理
· 在.NET Core中使用异步多线程高效率的处理大量数据
阅读排行:
· 用 Cursor 写出第一个程序
· 如何做好技术经理
· 《HelloGitHub》第 105 期
· 盘点5个常用的.Net依赖注入框架!
· 一句话,我让 AI 帮我做了个 P 图网站!
点击右上角即可分享
微信分享提示