黑马程序员——java基础——集合框架(2)Map

时间:2021-08-26 11:30:04
------ Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------



一、Map集合

1、Map集合概述:

    Map<K,V>集合是一个接口,和List集合及Set集合不同的是,它是双列集合,并且可以给对象加上名字,即键(Key)

1)Map特点:

    a)该集合存储键值对,一对一对往里存

    b)要保证键的唯一性。

2)Map体系

    Map

|--Hashtable:底层是哈希表数据结构,是线程同步的。不可以存储null键,null值,效率低。

|--HashMap:底层是哈希表数据结构,是线程不同步的。可以存储null键,null值。替代了Hashtable,效率高。

|--TreeMap:底层是二叉树结构,可以对map集合中的键进行指定顺序的排序。

3)Map集合存储和Collection的区别:

    Collection一次存一个元素;Map一次存一对元素。

    Collection是单列集合;Map是双列集合。

    Map中的存储的一对元素:一个是键,一个是值,键与值之间有对应(映射)关系。

    特点:要保证map集合中键的唯一性。


2、Map集合共性方法

1)添加。

    V put(K key,V value);//当存储的键相同时,新的值会替换老的值,并将老值返回。如果键没有重复,返回null。

    void putAll(Map);//添加一个Map集合

2)删除。

    void clear():清空

    value remove(key) ;//删除指定键。

3)判断。

    boolean isEmpty();//是否含有元素

    boolean containsKey(key);//是否包含key

    boolean containsValue(value) ;//是否包含value

4)取出。

    int size();//返回长度

    value get(key) ;//通过指定键获取对应的值。如果返回null,可以判断该键不存在。当然有特殊情况,就是在hashmap集合中,是可以存储null键null值的。

    Collection values();//获取map集合中的所有的值。


3、Map集合的两种遍历方式

    原理:Map中是没有迭代器的,而Collection具备迭代器,只要将Map集合转成Set集合,就可以使用迭代器了。之所以转成Set,是因为Map集合具备着键的唯一性,其实Set集合就来自于Map,Set集合底层其实用的就是Map的方法。

1)遍历Map集合方式一:Set keySet()方法。

    可以将map集合中的键都取出存放到set集合中。对set集合进行迭代。迭代完成,再通过get方法对获取到的键进行值的获取。

2)遍历Map集合方式二:Set entrySet()方法,取的是键和值的映射关系。

    Entry是Map接口中的内部接口,通过entrySet()方法把Map集合中的对应关系取出来,作为Map.Entry类型的元素存入Set集合中,由内部接口Map.Entry中的getKey()和getValue()方法可以分别获得对应关系的键和值。迭代Set集合中的对应关系,就可以获得Map集合的左右元素。

    为什么要定义在map内部呢?entry是访问键值关系的入口,是map的入口,访问的是map中的键值对。

代码示例:

//通过两种方法遍历Map集合中的元素

import java.util.*;

class MapDemo {

         publicstatic void main(String[] args) {

                   Map<String,String>map = new HashMap<String,String>();//定义一个HashMap集合

                   map.put("02","zhangsan2");//添加元素

                   map.put("03","zhangsan3");

                   map.put("01","zhangsan1");

                   map.put("04","zhangsan4");

                   //-----方式一-------

                   //先获取map集合的所有键的Set集合,keySet();

                   Set<String>keySet = map.keySet();

                   //有了Set集合。就可以获取其迭代器。

                   Iterator<String>it = keySet.iterator();

                   while(it.hasNext()){

                            Stringkey = it.next();

                            //有了键可以通过map集合的get方法获取其对应的值。

                            Stringvalue  = map.get(key);

                            System.out.println("key:"+key+",value:"+value);

                   }

                   //-----方式一-------

                   //Map集合中的映射关系取出。存入到Set集合中。

                   Set<Map.Entry<String,String>>entrySet = map.entrySet();

                  //获取迭代器

                   Iterator<Map.Entry<String,String>>it = entrySet.iterator();

                   while(it.hasNext()){

                            Map.Entry<String,String>me = it.next();

                            //通过getKey()方法获取键,getValue()方法获取值

                            Stringkey = me.getKey();

                            Stringvalue = me.getValue();

                            System.out.println(key+":"+value);

                   }

         }

}

 

4、Map应用及扩展

         a) 当量数据之间存在着映射关系的时候,我们就应该想到使用Map集合。

       代码示例:

       /*需求:获取一个字符串中各字母出现的次数。

希望打印结果:a(1)c(2).....

         思路:

1将字符串转换成字符数组。因为要对每一个字母进行操作。

2定义一个map集合,因为打印结果的字母有顺序,所以使用treemap集合。

3,遍历字符数组。

                   将每一个字母作为键去查map集合。

                   如果返回null,将该字母和1存入到map集合中。

                   如果返回不是null,说明该字母在map集合已经存在并有对应次数。那么就获取该次数并进行自增。,然后将该字母和自增后的次数存入到map集合中。覆盖调用原理键所对应的值。

4,将map集合中的数据变成指定的字符串形式返回。

       */

import java.util.*;

class MapTest{

         publicstatic void main(String[] args) {

                   Strings= charCount("ak+abAf1c,dCkaAbc-defa");

                   System.out.println(s);

         }

         publicstatic String charCount(String str){ //定义获取字符出现次数的方法

                   char[]chs = str.toCharArray(); //把字符串转成一个字符数组

                   TreeMap<Character,Integer>tm = new TreeMap<Character,Integer>();

int count = 0;//定义一个计数器

                   for(intx=0; x<chs.length; x++){

                            if(!(chs[x]>='a'&& chs[x]<='z' || chs[x]>='A' && chs[x]<='Z'))//判断是否为字母

                                     continue;

                            Integervalue = tm.get(chs[x]);

                            if(value!=null)//判断Map集合中有没有这个字母

                                     count= value;

                            count++;

                            tm.put(chs[x],count);

//直接往集合中存储字符和数字,为什么可以,因为自动装箱。

                            count= 0; //每次循环后计数器归零

                   }

StringBuilder sb = new StringBuilder();//定义一个容器来接受不定长的字符串

                   //遍历Map集合

Set<Map.Entry<Character,Integer>> entrySet =tm.entrySet();

                   Iterator<Map.Entry<Character,Integer>>  it = entrySet.iterator();

                   while(it.hasNext()){

                            Map.Entry<Character,Integer>me = it.next();

                            Characterch = me.getKey();

                            Integervalue = me.getValue();

                            sb.append(ch+"("+value+")");

                   }

                   returnsb.toString();

         }

}

        

         b) 在很多项目中,应用比较多的是一对多的映射关系,这就可以通过嵌套的形式将多个映射定义到一个大的集合中,并将大的集合分级处理,形成一个体系。

代码示例:

/*

map扩展。

map集合被使用是因为具备映射关系。

以下是班级对应学生,而学生中学号对应着姓名的映射关系:

"yureban"   Student("01""zhangsan");

"yureban"   Student("02" "lisi");

"jiuyeban""01" "wangwu";

"jiuyeban""02" "zhaoliu";

就如同一个学校有多个教室。每一个教室都有名称。

*/

import java.util.*;

class MapExpandKnow{

         publicstatic void main(String[] args) {

                   //预热班集合

                   HashMap<String,String>yureban=new HashMap<String,String>();

                   //就业班集合

                   HashMap<String,String>jiuyeban=new HashMap<String,String>();

                   //学校集合

HashMap<String,HashMap<String,String>>czbk=newHashMap<String,HashMap<String,String>>();

                   //学校中班级集合和名称的映射

                   czbk.put("yureban",yureban);

                   czbk.put("jiuyueban",jiuyeban);

//预热班级中学号与姓名的映射

                   yureban.put("01","zhangsan");

                   yureban.put("02","lisi");

                   //就业班级中学号与姓名的映射

                   jiuyeban.put("01","wangwu");

                   jiuyeban.put("02","zhouqi");

                   //直接显示全部学生信息

                   getAllStudentInfo(czbk);

         }

         //定义一个方法获取全部学生信息,包括在哪个班级,叫什么名字,学号多少

         publicstatic void getAllStudentInfo(HashMap<String,HashMap<String,String>> hm){

                   for(Iterator<String> it=hm.keySet().iterator();it.hasNext() ; ) {//keySet取出方式

                            Strings= it.next();//班级名称

                            System.out.println(s+":");

                            HashMap<String,String>stu=hm.get(s);//班级集合

                            getStudentInfo(stu);

                   }

         }

         //获取班级中学生的信息,包括姓名和学号

         publicstatic void getStudentInfo(HashMap<String,String> hm){

                   for(Iterator<String> it=hm.keySet().iterator();it.hasNext() ; ){

                            Stringkey=it.next();//学号

                            Stringvalue=hm.get(key);//姓名

                            System.out.println(key+"..."+value);

                   }

         }

}


5、使用集合的技巧:

1)看到Array就是数组结构,有角标,查询速度很快。

2)看到link就是链表结构:增删速度快,而且有特有方法。

3)看到hash就是哈希表,就要想要哈希值,就要想到唯一性,就要想到存入到该结构的中的元素必须覆盖hashCode,equals方法。

4)看到tree就是二叉树,就要想到排序,就想要用到比较。

比较的两种方式:

一个是Comparable:覆盖compareTo方法;

一个是Comparator:覆盖compare方法。

5)LinkedHashSet,LinkedHashMap:这两个集合可以保证哈希表有存入顺序和取出顺序一致,保证哈希表有序。

6)集合什么时候用?

当存储的是一个元素时,就用Collection。当存储对象之间存在着映射关系时,就使用Map集合。

要保证唯一,就用Set。不保证唯一,就用List。