Home Java集合框架 之 Map接口
Post
Cancel

Java集合框架 之 Map接口

Map接口有以下几个常见的实现类:

HashMap

元素为键值对,键具有唯一性

  • JDK 1.8中基于位桶 + 链表 + 红黑树实现
  • 线程不安全
  • 键无序

构造方法

默认构造方法:

1
HashMap<Key, Value> map = new HashMap<>();

也可以在构造时指定 容量(Capacity)负载因子(loadFactor),例:

1
HashMap<Key, Value> map = new HashMap<>(8, 0.5f);

常用方法

方法描述
put(K, V)将键值对添加至map中,若键已存在则更新值
get(K)返回指定键对应的值,若键不存在则返回null
getOrDefault(K, defaultValue)返回指定键对应的值,若键不存在则返回指定的defaultValue
containsKey(K)判断指定的键是否在map中
remove(K)删除指定键及其对应的值,并返回该值,若键不存在则返回null
keySet()返回map中所有键的集合
values()返回map中所有值的集合
entrySet()返回map中所有映射关系的集合

代码示例:

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
import java.util.*;

public class hashmap{
    public static void main(String[] args){
        /* initialization */
        Character[] letters = {'a', 'b', 'c', 'd', 'e'};
        Integer[] nums = {1, 2, 3, 4, 5};
        HashMap<Character, Integer> alpha2num = new HashMap<>();

        for (int i = 0; i < letters.length; i++){
            alpha2num.put(letters[i], nums[i]);
        }
        print("map:", alpha2num);

        /* get */
        print("get c:", alpha2num.get('c'));
        print("get r:", alpha2num.get('r'));

        /* getOrDefault */
        print("get or default c:", alpha2num.getOrDefault('c', 10));
        print("get or default r:", alpha2num.getOrDefault('r', 10));

        /* containsKey */
        print("contains b:", alpha2num.containsKey('b'));

        /* remove */
        print("remove d:", alpha2num.remove('d'));
        print("remove r:", alpha2num.remove('r'));
        print("current map:", alpha2num);

        /* keySet */
        print("key set:", alpha2num.keySet());

        /* values */
        print("values:", alpha2num.values());

        /* entrySet */
        printEntry("k-v pairs:", alpha2num.entrySet());
    }

    public static void print(String prompt, HashMap<Character, Integer> map){
        System.out.println(String.format("%-20s %-20s", prompt, map));
    }

    public static void print(String prompt, Integer num){
        System.out.println(String.format("%-20s %-20s", prompt, num));
    }

    public static void print(String prompt, boolean flag){
        System.out.println(String.format("%-20s %-20s", prompt, flag));
    }

    public static void print(String prompt, Set<Character> keys){
        System.out.println(String.format("%-20s %-20s", prompt, keys));
    }

    public static void print(String prompt, Collection<Integer> values){
        System.out.println(String.format("%-20s %-20s", prompt, values));
    }

    public static void printEntry(String prompt, Set<Map.Entry<Character, Integer>> entry){
        System.out.println(String.format("%-20s %-20s", prompt, entry));
    }
}

输出:

1
2
3
4
5
6
7
8
9
10
11
12
map:                 {a=1, b=2, c=3, d=4, e=5}
get c:               3                   
get r:               null                
get or default c:    3                   
get or default r:    10                  
contains b:          true                
remove d:            4                   
remove r:            null                
current map:         {a=1, b=2, c=3, e=5}
key set:             [a, b, c, e]        
values:              [1, 2, 3, 5]        
k-v pairs:           [a=1, b=2, c=3, e=5]

遍历方式

可以遍历map中的键值对,遍历时使用forEach

1
2
3
for (Character key: alpha2num.keySet()) System.out.print(key + " ");
for (Integer value: alpha2num.values()) System.out.print(value + " ");
for (Map.Entry<Character, Integer> entry: alpha2num.entrySet()) System.out.print("(" + entry + " " + entry.getKey() + " " + entry.getValue() + ") ");

输出:

1
2
3
a b c e 
1 2 3 5 
(a=1 a 1) (b=2 b 2) (c=3 c 3) (e=5 e 5)

LinkedHashMap

LinkedHashMap是HashMap的子类,其构造与常用方法与HashMap一致。在LinkedHashMap内部维护着一个双向链表,这使得其中的键有序。关于键的无序与有序性,验证如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.*;

public class linkedhashmap {
    public static void main(String[] args){
        HashMap<Integer, Integer> map1 = new HashMap<>();
        LinkedHashMap<Integer, Integer> map2 = new LinkedHashMap<>();
        Integer[] nums = {3, 4, 1, 2};

        for (Integer num: nums){
            map1.put(num, null);
            map2.put(num, null);
        }

        System.out.print(String.format("%-25s", "HashMap keys:"));
        for (Integer key: map1.keySet()) System.out.print(key + " ");

        System.out.println("");

        System.out.print(String.format("%-25s", "LinkedHashMap keys:"));
        for (Integer key: map2.keySet()) System.out.print(key + " ");
    }
}

输出:

1
2
HashMap keys:            1 2 3 4 
LinkedHashMap keys:      3 4 1 2 

TreeMap

是Map的子接口SortedMap的实现类,其内部的键会被排序。默认为升序排序,也可以使用Comparator自定义排序方式。

构造方法

1
TreeMap<K, V> map = new TreeMap<>();

常用方法

关于操作与访问TreeMap的方法与HashMap中提到的一致。除此之外,它还提供了各种导航方法,效果与TreeSet中类似的方法一致:

方法描述
firstKey()
lastKey()
返回第一个键
返回最后一个键
higherKey(K)
ceilingKey(K)
返回map中大于指定键的最小键
返回map中大于等于指定键的最小键
lowerKey(K)
floorKey(K)
返回map中小于指定键的最大键
返回map中小于等于指定键的最大键
pollFirstEntry()
pollLastEntry()
返回并删除第一个键值对
返回并删除最后一个键值对
headMap(K, boolean b)返回指定键之前的所有键值对,b默认为false,不包含边界
tailMap(K, boolean b)返回指定键之后的所有键值对,b默认为true,包含边界
subMap(K1, boolean b1, K2, boolean b2)返回指定键之间的所有键值对,b1默认为trueb2默认为false,左闭右开

代码示例:

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
import java.util.*;

public class treemap {
    public static void main(String[] args){
        /* initialization */
        Character[] letters = {'a', 'd', 'e', 'c', 'b', 'g', 'f'};
        Integer[] nums = {3, 4, 2, 1, 5, 7, 6};
        TreeMap<Character, Integer> map1 = new TreeMap<>();

        for (int i = 0; i < letters.length; i++) map1.put(letters[i], nums[i]);
        print("treemap:", map1);
        TreeMap<Character, Integer> map2 = new TreeMap<>(Comparator.comparing(map1::get));
        map2.putAll(map1);
        print("sort by value:",  map2);

        /* firstKey & lastKey */
        print("map1 first:", map1.firstKey());
        print("map1 last:", map1.lastKey());

        /* higherKey & ceilingKey */
        print("higher key c:", map1.higherKey('c'));
        print("ceiling key c:", map1.ceilingKey('c'));

        /* lowerKey & floorKey() */
        print("lower key b:", map1.lowerKey('b'));
        print("flooring key b:", map1.floorKey('b'));

        /* poll */
        print("poll first:", map1.pollFirstEntry());
        print("poll last", map1.pollLastEntry());
        print("current treemap:", map1);

        /* headMap */
        print("head c:", map1.headMap('c', true));

        /* tailMap */
        print("tail c:", map1.tailMap('c', false));

        /* subMap */
        print("sub b to e:", map1.subMap('b', false, 'e', true));
    }
    
    public static void print(String prompt, TreeMap<Character, Integer> map){
        System.out.println(String.format("%-25s %-25s", prompt, map));
    }

    public static void print(String prompt, Character key){
        System.out.println(String.format("%-25s %-25s", prompt, key));
    }

    public static void print(String prompt, Map.Entry<Character, Integer> entry){
        System.out.println(String.format("%-25s %-25s", prompt, entry));
    }

    public static void print(String prompt, NavigableMap<Character, Integer> map){
        System.out.println(String.format("%-25s %-25s", prompt, map));
    }
}

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
treemap:                  {a=3, b=5, c=1, d=4, e=2, f=6, g=7}
sort by value:            {c=1, e=2, a=3, d=4, b=5, f=6, g=7}
map1 first:               a                        
map1 last:                g                        
higher key c:             d                        
ceiling key c:            c                        
lower key b:              a                        
flooring key b:           b                        
poll first:               a=3                      
poll last                 g=7                      
current treemap:          {b=5, c=1, d=4, e=2, f=6}
head c:                   {b=5, c=1}               
tail c:                   {d=4, e=2, f=6}          
sub b to e:               {c=1, d=4, e=2} 

HashTable

  • 旧版本的遗留类
  • 不允许键或值为null
  • 线程安全,但多线程场景现如今多用ConcurrentHashMap
  • 不推荐使用

参考

This post is licensed under CC BY 4.0 by the author.