【JAVA集合框架之Map】

一、概述。
1.Map是一种接口,在JAVA集合框架中是以一种非常重要的集合。
2.Map一次添加一对元素,所以又称为“双列集合”(Collection一次添加一个元素,所以又称为“单列集合”)
3.Map集合中存放的是一个一个的键值对,集合中存放的元素必须保证键的唯一性。
二、常用方法。
1.添加

 V put(K key, V value)
          将指定的值与此映射中的指定键关联(可选操作)。

该方法的作用就是向集合中添加一个键值对,并返回一个值;如果键存在,则返回对应的旧值,并以新值取代之;如果键不存在则返回null。所以该方法也是修改的方法。

void putAll(Map<? extends K,? extends V> m)
          从指定映射中将所有映射关系复制到此映射中(可选操作)。

该方法功能略,但注意泛型上限的使用。比较Collection方法:

 boolean addAll(Collection<? extends E> c)
          将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。


2.删除

 V remove(Object key)
          如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。

该方法根据键删除一个键值对,并返回值。如果没有这个键值对,将返回null。

 void clear()
          从此映射中移除所有映射关系(可选操作)。

该方法功能就是清空集合。
3.判断

 boolean containsKey(Object key)
          如果此映射包含指定键的映射关系,则返回 true
 boolean containsValue(Object value)
          如果此映射将一个或多个键映射到指定值,则返回 true

这两个方法,前者判断是否存在指定键,后者判断是否存在指定值。

 boolean isEmpty()
          如果此映射未包含键-值映射关系,则返回 true

该方法用于判断该Map集合是否为空集合。
4.获取。

 V get(Object key)
          返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null
 int size()
          返回此映射中的键-值映射关系数。

这两个方法,前者根据指定的键获取对应的值,如果集合中没有指定的键,则返回null;后者获取键值对的个数。

以上的方法为基本方法,重点方法在下面。

三、重点:Map集合的四种遍历方式。

1.第一种遍历方式:使用keySet方法。

 Set<K> keySet()
          返回此映射中包含的键的 Set 视图。

该方法会返回一个包含所有键的Set集合。

遍历过程:先得到所有键的集合,遍历集合,根据键得到所有的值。

 1 package p01.traverseDemo01.keySetDemo;
 2 
 3 import java.util.HashMap;
 4 import java.util.Iterator;
 5 import java.util.Map;
 6 import java.util.Set;
 7 
 8 public class KeySetDemo {
 9 
10     public static void main(String[] args) {
11         Demo01();
12     }
13 
14     private static void Demo01() {
15         Map<Integer,String>map=new HashMap<Integer,String>();
16         map.put(1, "wangcai");
17         map.put(2, "xiaoqiang");
18         map.put(3, "xiaoming");
19         
20         Set<Integer>set=map.keySet();
21         for(Iterator<Integer>it=set.iterator();it.hasNext();)
22         {
23             Integer key=it.next();
24             String value=map.get(key);
25             System.out.println(key+":"+value);
26         }
27         
28     }
29 
30 }
View Code

应当注意,结果是无序的,这是因为采用了HashMap作为示例,HashMap底层的数据结构是哈希表,存储元素的时候有自己的规则,所以无序。

2.第二种遍历方式:使用entrySet方法。

 Set<Map.Entry<K,V>> entrySet()
          返回此映射中包含的映射关系的 Set 视图。

此方法返回值也是一个Set集合,但是存储的内容是Map.Entry对象。Map.Entry是什么东西?

JDK1.6API的解释如下:

嵌套类摘要
static interface Map.Entry<K,V>
          映射项(键-值对)。

虽然API的解释是“嵌套类”,但是Map是一个接口,Entry也是一个接口,事实上Map.Entry是Map的一个内部静态接口。

该接口封装了几个方法,用于操作一个键值对,注意,是一个,因为它仅仅对一个键值对进行封装(确切的说是对操作每个键值对的方法进行了封装,每个键值对对应着一个Map.Entry对象)。

Map.Entry接口的方法如下:

方法摘要
 boolean equals(Object o)
          比较指定对象与此项的相等性。
 K getKey()
          返回与此项对应的键。
 V getValue()
          返回与此项对应的值。
 int hashCode()
          返回此映射项的哈希码值。
 V setValue(V value)
          用指定的值替换与此项对应的值(可选操作)。

以上方法中,最常用的是getKey方法和getValue方法。

遍历过程:首先拿到每一个键值对对象Map.Entry的集合,再通过遍历集合拿到所有的键值对。

 1 package p01.traverseDemo01.keySetDemo;
 2 
 3 import java.util.HashMap;
 4 import java.util.Iterator;
 5 import java.util.Map;
 6 import java.util.Set;
 7 
 8 public class KeySetDemo {
 9 
10     public static void main(String[] args) {
11         Demo01();
12     }
13 
14     private static void Demo01() {
15         Map<Integer,String>map=new HashMap<Integer,String>();
16         map.put(1, "wangcai");
17         map.put(3, "xiaoming");
18         map.put(2, "xiaoqiang");
19         
20         
21         Set<Integer>set=map.keySet();
22         for(Iterator<Integer>it=set.iterator();it.hasNext();)
23         {
24             Integer key=it.next();
25             String value=map.get(key);
26             System.out.println(key+":"+value);
27         }
28         
29     }
30 
31 }
View Code

3.第三种遍历方式:使用values方法。

 Collection<V> values()
          返回此映射中包含的值的 Collection 视图。

此种方法可以返回值的Collection集合,比较返回值,第一种方式使用keySet方法,返回值类型是Set集合,这里为什么不是Set集合?

解析:Map中键是唯一的,所以使用Set集合存储,而值可以重复,所以使用Collection集合存储。

 1 package p01.traverseDemo03.valuesDemo;
 2 
 3 import java.util.Collection;
 4 import java.util.HashMap;
 5 import java.util.Iterator;
 6 import java.util.Map;
 7 import java.util.Set;
 8 
 9 public class ValuesDemo {
10 
11     public static void main(String[] args) {
12         Demo01();
13     }
14 
15     private static void Demo01() {
16         Map<Integer,String>map=new HashMap<Integer,String>();
17         map.put(1, "wangcai");
18         map.put(3, "xiaoming");
19         map.put(2, "xiaoqiang");
20         
21         
22         Collection<String>coll=map.values();
23         for(Iterator<String>it=coll.iterator();it.hasNext();)
24         {
25             String value=it.next();
26             System.out.println(value);
27         }
28         
29     }
30 
31 }
View Code

4.第四种遍历方式:使用增强型for循环间接遍历。

 1 package p11.ArraysDemo.p01.ExtendForCircle;
 2 
 3 import java.util.Collection;
 4 import java.util.HashMap;
 5 import java.util.Map;
 6 import java.util.Set;
 7 
 8 /**
 9  * 使用增强型for循环实现Map的三种遍历方式
10  * @author kuangdaoyizhimei
11  *
12  */
13 public class ExtendForCircle {
14 
15     public static void main(String[] args) {
16         Map<Integer,String>map=new HashMap<Integer,String>();
17         map.put(1, "xiaoqiang");
18         map.put(2, "zhangsan");
19         map.put(3, "lisi");
20         map.put(4, "wangwu");
21         Function1(map);
22         Function2(map);
23         Function3(map);
24     }
25 
26     private static void Function3(Map<Integer, String> map) {
27         Set<Map.Entry<Integer, String>>set=map.entrySet();
28         for(Map.Entry<Integer, String>kv:set)
29         {
30             Integer key=kv.getKey();
31             String value=kv.getValue();
32             System.out.println("Key:"+key+"	value:"+value);
33         }
34     }
35 
36     private static void Function2(Map<Integer, String> map) {
37         Collection<String>list=map.values();
38         for(String val:list)
39         {
40             System.out.println(val);
41         }
42         System.out.println();
43         System.out.println();
44     }
45 
46     private static void Function1(Map<Integer, String> map) {
47         Set<Integer>set=map.keySet();
48         for(Integer i:set)
49         {
50             System.out.println(i+":"+map.get(i));
51         }
52         System.out.println();
53         System.out.println();
54     }
55 
56 }
View Code

四、Map集合的常见子类。

public class Hashtable<K,V>extends Dictionary<K,V>implements Map<K,V>, Cloneable, Serializable
public class HashMap<K,V>extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable
public class TreeMap<K,V>extends AbstractMap<K,V>implements NavigableMap<K,V>, Cloneable, Serializable

这三者有些区别:

HashTable:内部结构是哈希表,JDK1.0就出现了(JDK1.0出现的单列集合只有Vector,双列集合只有HashTable),是同步的。不允许null作为键值。
HashMap:内部结构是哈希表,是非同步的。允许null作为键值。
TreeMap:内部结构是一棵红黑树,可以对Map集合中的键进行排序。

需要注意的是Set集合的实现依赖于HashMap集合----HashMap将值统一为一个对象而只关注键的操作即可实现Set集合中元素的唯一性。

HashTable有一个子类应当特别注意:Properties

public class Propertiesextends Hashtable<Object,Object>

这个类用来存储键值对型的文件配置信息,它和Io技术相结合才能发挥出它的优势。

1.HashMap类。

Hash代表着底层的实现使用了哈希表,所以如果使用自定义对象作为键,应当注意重写类的hashCode方法和equals方法。

示例:使用HashMap存储自定义对象Student和其归属地NativePlace,并遍历。

  1 package p02.SubClassDemo01.HashMapDemo;
  2 
  3 import java.util.HashMap;
  4 import java.util.Iterator;
  5 import java.util.Map;
  6 
  7 class Student 
  8 {
  9     private String name;
 10     private int age;
 11     @Override
 12     public int hashCode() {
 13         final int prime = 31;
 14         int result = 1;
 15         result = prime * result + age;
 16         result = prime * result + ((name == null) ? 0 : name.hashCode());
 17         return result;
 18     }
 19     @Override
 20     public boolean equals(Object obj) {
 21         if (this == obj)
 22             return true;
 23         if (obj == null)
 24             return false;
 25         if (getClass() != obj.getClass())
 26             return false;
 27         Student other = (Student) obj;
 28         if (age != other.age)
 29             return false;
 30         if (name == null) {
 31             if (other.name != null)
 32                 return false;
 33         } else if (!name.equals(other.name))
 34             return false;
 35         return true;
 36     }
 37     public Student(String name, int age) {
 38         super();
 39         this.name = name;
 40         this.age = age;
 41     }
 42     public Student() {
 43         super();
 44     }
 45     public String getName() {
 46         return name;
 47     }
 48     public void setName(String name) {
 49         this.name = name;
 50     }
 51     public int getAge() {
 52         return age;
 53     }
 54     public void setAge(int age) {
 55         this.age = age;
 56     }
 57 }
 58 
 59 class NativePlace
 60 {
 61     private String province;
 62     private String city;
 63     public NativePlace(String province, String city) {
 64         super();
 65         this.province = province;
 66         this.city = city;
 67     }
 68     public NativePlace() {
 69         super();
 70     }
 71     public String getProvince() {
 72         return province;
 73     }
 74     public void setProvince(String province) {
 75         this.province = province;
 76     }
 77     public String getCity() {
 78         return city;
 79     }
 80     public void setCity(String city) {
 81         this.city = city;
 82     }
 83 }
 84 public class HashMapDemo {
 85 
 86     public static void main(String[] args) {
 87         Demo01();
 88     }
 89 
 90     private static void Demo01() {
 91         HashMap<Student,NativePlace>hm=new HashMap<Student,NativePlace>();
 92         hm.put(new Student("wangwu",25), new NativePlace("hubei","suizhou"));
 93         hm.put(new Student("zhaoliu",26), new NativePlace("hunan","chagnsha"));
 94         hm.put(new Student("zhangsan",23), new NativePlace("shandong","zibo"));
 95         hm.put(new Student("lisi",24), new NativePlace("shandong","weifang"));
 96         
 97         //重复添加无效
 98         hm.put(new Student("wangwu",25), new NativePlace("hubei","suizhou"));
 99         hm.put(new Student("zhaoliu",26), new NativePlace("hunan","chagnsha"));
100         hm.put(new Student("zhangsan",23), new NativePlace("shandong","zibo"));
101         hm.put(new Student("lisi",24), new NativePlace("shandong","weifang"));
102         
103         for(Iterator<Map.Entry<Student,NativePlace>>it=hm.entrySet().iterator();it.hasNext();)
104         {
105             Map.Entry<Student, NativePlace>me=it.next();
106             Student stu=me.getKey();
107             NativePlace np=me.getValue();
108             System.out.println(stu.getName()+":"+np.getProvince()+"."+np.getCity());
109         }
110         
111         
112     }
113 
114 }
View Code

2.TreeMap类。

TreeMap类底层使用了排序树,如果使用自定义对象作为键,就必须实现Comparable接口;如果没有实现这个接口,则必须使用比较器作为HashTree初始化对象的参数。

现在将上面的代码中Student的hashCode方法以及equals方法删掉,同时实现接口Comparable,重写compareTo方法,以达到按照年龄排序的目的。

 1 package p02.SubClassDemo02.TreeMapDemo;
 2 
 3 import java.util.Iterator;
 4 import java.util.Map;
 5 import java.util.TreeMap;
 6 
 7 class Student implements Comparable<Student>
 8 {
 9     private String name;
10     private int age;
11     public Student(String name, int age) {
12         super();
13         this.name = name;
14         this.age = age;
15     }
16     public Student() {
17         super();
18     }
19     public String getName() {
20         return name;
21     }
22     public void setName(String name) {
23         this.name = name;
24     }
25     public int getAge() {
26         return age;
27     }
28     public void setAge(int age) {
29         this.age = age;
30     }
31     @Override
32     public int compareTo(Student o) {
33         int temp=this.age-o.getAge();
34         return temp==0?this.name.compareTo(o.getName()):temp; 
35     }
36 }
37 
38 class NativePlace
39 {
40     private String province;
41     private String city;
42     public NativePlace(String province, String city) {
43         super();
44         this.province = province;
45         this.city = city;
46     }
47     public NativePlace() {
48         super();
49     }
50     public String getProvince() {
51         return province;
52     }
53     public void setProvince(String province) {
54         this.province = province;
55     }
56     public String getCity() {
57         return city;
58     }
59     public void setCity(String city) {
60         this.city = city;
61     }
62 }
63 
64 public class TreeMapDemo {
65 
66     public static void main(String[] args) {
67         Demo01();
68     }
69 
70     private static void Demo01() {
71         TreeMap<Student,NativePlace>hm=new TreeMap<Student,NativePlace>();
72         hm.put(new Student("wangwu",25), new NativePlace("hubei","suizhou"));
73         hm.put(new Student("zhaoliu",26), new NativePlace("hunan","chagnsha"));
74         hm.put(new Student("zhangsan",23), new NativePlace("shandong","zibo"));
75         hm.put(new Student("lisi",24), new NativePlace("shandong","weifang"));
76         
77         //重复添加无效
78         hm.put(new Student("wangwu",25), new NativePlace("hubei","suizhou"));
79         hm.put(new Student("zhaoliu",26), new NativePlace("hunan","chagnsha"));
80         hm.put(new Student("zhangsan",23), new NativePlace("shandong","zibo"));
81         hm.put(new Student("lisi",24), new NativePlace("shandong","weifang"));
82         
83         for(Iterator<Map.Entry<Student,NativePlace>>it=hm.entrySet().iterator();it.hasNext();)
84         {
85             Map.Entry<Student, NativePlace>me=it.next();
86             Student stu=me.getKey();
87             NativePlace np=me.getValue();
88             System.out.println(stu.getName()+":"+stu.getAge()+"----"+np.getProvince()+"."+np.getCity());
89         }
90         
91         
92     }
93 
94 }
View Code

运行可以看出重复添加的元素仍然没有添加进去,因为TreeSet判断元素是否相同的依据是compareTo方法的返回值而不是hashCode方法以及equals方法。

如果现在有了新的需求,需要按照新的规则对学生进行排序,则创建比较器,按照比较器中的新规则进行排序。

  1 package p02.SubClassDemo02.TreeMapDemo;
  2 
  3 import java.util.Comparator;
  4 import java.util.Iterator;
  5 import java.util.Map;
  6 import java.util.TreeMap;
  7 
  8 class Student implements Comparable<Student>
  9 {
 10     private String name;
 11     private int age;
 12     public Student(String name, int age) {
 13         super();
 14         this.name = name;
 15         this.age = age;
 16     }
 17     public Student() {
 18         super();
 19     }
 20     public String getName() {
 21         return name;
 22     }
 23     public void setName(String name) {
 24         this.name = name;
 25     }
 26     public int getAge() {
 27         return age;
 28     }
 29     public void setAge(int age) {
 30         this.age = age;
 31     }
 32     @Override
 33     public int compareTo(Student o) {
 34         int temp=this.age-o.getAge();
 35         return temp==0?this.name.compareTo(o.getName()):temp; 
 36     }
 37 }
 38 
 39 class NativePlace
 40 {
 41     private String province;
 42     private String city;
 43     public NativePlace(String province, String city) {
 44         super();
 45         this.province = province;
 46         this.city = city;
 47     }
 48     public NativePlace() {
 49         super();
 50     }
 51     public String getProvince() {
 52         return province;
 53     }
 54     public void setProvince(String province) {
 55         this.province = province;
 56     }
 57     public String getCity() {
 58         return city;
 59     }
 60     public void setCity(String city) {
 61         this.city = city;
 62     }
 63 }
 64 
 65 class CompareByName implements Comparator<Student>
 66 {
 67     @Override
 68     public int compare(Student o1, Student o2) {
 69         int temp=o1.getName().compareTo(o2.getName());
 70         return temp==0?o1.getAge()-o2.getAge():temp;
 71     }
 72 }
 73 public class TreeMapDemo {
 74     public static void main(String[] args) {
 75         Demo01();
 76     }
 77 
 78     private static void Demo01() {
 79         TreeMap<Student,NativePlace>hm=new TreeMap<Student,NativePlace>(new CompareByName());
 80         hm.put(new Student("wangwu",25), new NativePlace("hubei","suizhou"));
 81         hm.put(new Student("zhaoliu",26), new NativePlace("hunan","chagnsha"));
 82         hm.put(new Student("zhangsan",23), new NativePlace("shandong","zibo"));
 83         hm.put(new Student("lisi",24), new NativePlace("shandong","weifang"));
 84         
 85         //重复添加无效
 86         hm.put(new Student("wangwu",25), new NativePlace("hubei","suizhou"));
 87         hm.put(new Student("zhaoliu",26), new NativePlace("hunan","chagnsha"));
 88         hm.put(new Student("zhangsan",23), new NativePlace("shandong","zibo"));
 89         hm.put(new Student("lisi",24), new NativePlace("shandong","weifang"));
 90         
 91         for(Iterator<Map.Entry<Student,NativePlace>>it=hm.entrySet().iterator();it.hasNext();)
 92         {
 93             Map.Entry<Student, NativePlace>me=it.next();
 94             Student stu=me.getKey();
 95             NativePlace np=me.getValue();
 96             System.out.println(stu.getName()+":"+stu.getAge()+"----"+np.getProvince()+"."+np.getCity());
 97         }
 98         
 99         
100     }
101 
102 }
View Code

可以看到,通过使用比较器,确实达到了按照名字字典序排序的目的,这也证明了如果使用比较器,则原来的自然比较方式将会无效。

3.LinkedHashMap类。

此类的是HashMap的子类,与HashMap相比,该类实现了“有序”,即插入和取出的顺序一致。该类在很多时候都能发挥出很大的作用。

原文地址:https://www.cnblogs.com/kuangdaoyizhimei/p/4020574.html