zoukankan      html  css  js  c++  java
  • 【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相比,该类实现了“有序”,即插入和取出的顺序一致。该类在很多时候都能发挥出很大的作用。

  • 相关阅读:
    Preliminaries for Benelux Algorithm Programming Contest 2019: I. Inquiry I
    Preliminaries for Benelux Algorithm Programming Contest 2019:A:Architecture
    pta刷题:L1-008 求整数段和 (10分)记录总结
    关系代数复习ing
    操作系统学习笔记:银行家算法浅谈
    mysql学习笔记:复习ing
    mysql学习笔记:集合运算并交差,其他
    JZOJ1900. 【2010集训队出题】矩阵
    【2019暑假】08.14比赛总结
    【2019暑假集训】08.13比赛总结
  • 原文地址:https://www.cnblogs.com/kuangdaoyizhimei/p/4020574.html
Copyright © 2011-2022 走看看