深入了解Map

联系

Java中的Map类似于OC的Dictionary,都是一个个键值对组成,一键对应一值。我在之前的文章中讲解过Set,其实在JAVA底层Set依赖的也是Map,那我们都知道,Set是单列的(只有值),而Map是双列的,怎么会是Set依赖Map呢?其实做法也很简单,Set将Key隐藏,只允许访问value就实现了Set的单列效果。

功能

*a:添加功能
    * V put(K key,V value):添加元素。
        * 如果键是第一次存储,就直接存储元素,返回null
        * 如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值

Map的遍历

方式一
  //通过获取所有的键来遍历值
        Map<String, Integer> map = new HashMap<>();
        map.put("张三", 23);
        map.put("李四", 24);
        map.put("王五", 25);
        map.put("赵六", 26);

        Set<String> keySet = map.keySet();            //获取所有键的集合
        Iterator<String> it = keySet.iterator();    //获取迭代器
        while(it.hasNext()) {                        //判断集合中是否有元素
            String key = it.next();                    //获取每一个键
            Integer value = map.get(key);            //根据键获取值
            System.out.println(key + "=" + value);
        }

使用迭代器遍历,但是有些复杂,可以改进

方式二 (方式一改进,较简单)

这种遍历方式类似于OC中for···in语法

        //使用增强for循环遍历
        for(String key : map.keySet()) {            //map.keySet()是所有键的集合
            System.out.println(key + "=" + map.get(key));
        }
方式三 键值对对象遍历
        //Map.Entry说明Entry是Map的内部接口,将键和值封装成了Entry对象,并存储在Set集合中
        Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
        //获取每一个对象
        Iterator<Map.Entry<String, Integer>> it = entrySet.iterator();
        while(it.hasNext()) {
            //获取每一个Entry对象
            Map.Entry<String, Integer> en = it.next();    //父类引用指向子类对象
            //Entry<String, Integer> en = it.next();    //直接获取的是子类对象
            String key = en.getKey();                    //根据键值对对象获取键
            Integer value = en.getValue();                //根据键值对对象获取值
            System.out.println(key + "=" + value);
        }
方式四 (方式三改进)
        for(Entry<String, Integer> en : map.entrySet()) {
            System.out.println(en.getKey() + "=" + en.getValue());
        }

LinkedHashMap

LinkedHashMap可以保证怎么存就怎么取

    public static void main(String[] args) {
        LinkedHashMap<String, Integer> lhm = new LinkedHashMap<>();
        lhm.put("张三", 23);
        lhm.put("李四", 24);
        lhm.put("赵六", 26);
        lhm.put("王五", 25);

        System.out.println(lhm);
    }

TreeMap

利用TreeMap可实现对键的自定义排序,同时键应为自定义类对象,同时需要在自定义类中重写compareTo方法,和hashSet里面的排序大致相同。

//按照Student的姓名排序,姓名相同按照年龄排序
public static void main(String[] args) {
        //demo1();
        TreeMap<Student, String> tm = new TreeMap<>(new Comparator<Student>() {

            @Override
            public int compare(Student s1, Student s2) {
                int num = s1.getName().compareTo(s2.getName());        //按照姓名比较
                return num == 0 ? s1.getAge() - s2.getAge() : num;
            }
        });
        tm.put(new Student("张三", 23), "北京");
        tm.put(new Student("李四", 13), "上海");
        tm.put(new Student("赵六", 43), "深圳");
        tm.put(new Student("王五", 33), "广州");

        System.out.println(tm);
    }

利用HashMap统计字符串中每个字符出现的次数

核心思想就是利用HashMap的containsKey()来判断是否重复。

/**
     * * A:案例演示
     * 需求:统计字符串中每个字符出现的次数
     * 
     * 分析:
     * 1,定义一个需要被统计字符的字符串
     * 2,将字符串转换为字符数组
     * 3,定义双列集合,存储字符串中字符以及字符出现的次数
     * 4,遍历字符数组获取每一个字符,并将字符存储在双列集合中
     * 5,存储过程中要做判断,如果集合中不包含这个键,就将该字符当作键,值为1存储,如果集合中包含这个键,就将值加1存储
     * 6,打印双列集合获取字符出现的次数
     */
    public static void main(String[] args) {
        //1,定义一个需要被统计字符的字符串
        String s = "aaaabbbbbccccccccccccc";
        //2,将字符串转换为字符数组
        char[] arr = s.toCharArray();
        //3,定义双列集合,存储字符串中字符以及字符出现的次数
        HashMap<Character, Integer> hm = new HashMap<>();
        //4,遍历字符数组获取每一个字符,并将字符存储在双列集合中
        for(char c: arr) {
            //5,存储过程中要做判断,如果集合中不包含这个键,就将该字符当作键,值为1存储,如果集合中包含这个键,就将值加1存储
            /*if(!hm.containsKey(c)) {            //如果不包含这个键
                hm.put(c, 1);
            }else {
                hm.put(c, hm.get(c) + 1);
            }*/
            hm.put(c, !hm.containsKey(c) ? 1 : hm.get(c) + 1);
        }
        //6,打印双列集合获取字符出现的次数

        for (Character key : hm.keySet()) {                //hm.keySet()代表所有键的集合
            System.out.println(key + "=" + hm.get(key));//hm.get(key)根据键获取值
        }
    }
案例演示:

集合嵌套之HashMap嵌套HashMap

需求:

一个年级有很多班,
一班定义为一个双列结合,键是学生对象,值是学生的归属地,
二班定义为一个双列结合,键是学生对象,值是学生的归属地。
无论一班二班都是班级对象,所以为了编译统一管理,把这些班级对象添加到某个年级中。

        //定义一班
        HashMap<Student, String> hm88 = new HashMap<>();
        hm88.put(new Student("张三", 23), "北京");
        hm88.put(new Student("李四", 24), "北京");
        hm88.put(new Student("王五", 25), "上海");
        hm88.put(new Student("赵六", 26), "广州");

        //定义二班
        HashMap<Student, String> hm99 = new HashMap<>();
        hm99.put(new Student("唐僧", 1023), "北京");
        hm99.put(new Student("孙悟空",1024), "北京");
        hm99.put(new Student("猪八戒",1025), "上海");
        hm99.put(new Student("沙和尚",1026), "广州");

        //定义年级
        HashMap<HashMap<Student, String>, String> hm = new HashMap<>();
        hm.put(hm88, "一班");
        hm.put(hm99, "二班");

        //遍历双列集合
        for(HashMap<Student, String> h : hm.keySet()) {        //hm.keySet()代表的是双列集合中键的集合
            String value = hm.get(h);                        //get(h)根据键对象获取值对象
            //遍历键的双列集合对象
            for(Student key : h.keySet()) {                    //h.keySet()获取集合总所有的学生键对象
                String value2 = h.get(key);

                System.out.println(key + "=" + value2 + "=" + value);
            }
        }

hashMap和hashTable的区别

共同点:

底层都是哈希算法,都是双列集合

区别:
  1. HashMap是线程不安全的,效率高,JDK1.2版本,Hashtable是线程安全的,效率低,JDK1.0版本的
  2. HashMap可以存储null键和null值,Hashtable不可以存储null键和null值
posted @ 2017-07-29 16:28  易之盛  阅读(505)  评论(0编辑  收藏  举报