zoukankan      html  css  js  c++  java
  • JavaSE集合(八)之Map

    前面给大家介绍了集合家族中的Collection家族,这一篇给大家分享的是集合中的另一个家族就是Map家族。以前的时候学习Map的时候没有很认真的去学习,我觉得很多东西还是不是很清楚。

    这次我将总结的非常详细。程序员的道理里,我们风雨无阻!

    一、Map接口

    1.1、Map概述

      Map 的字面翻译是映射(地图就是一种映射)。将键映射到值的对象,一个映射不能包含重复的键(如果有添加有重复的键,后面的会覆盖掉前面的,但是如果是自定义类型必须重写hashCode()和equals()方法),每个键最多只能映射到一个值。

      map是Java中提供的一种通用的元素存储方式,它是一种集合类。map集合类用于存储键值对(“键”、“值”)即Map<key,value>,每个键映射到一个值。但要注意的是:key不能重复。所以通过指定的key就可以取出对应的value。

        

      在JavaSE中,对Map的实现主要包括: HashMap, TreeMap, HashTable 和 LinkedHashMap:

    • HashMap 使用哈希表(hash table)实现, 在 keys 和/或 values 之中,都是无序的.
    • TreeMap 基于红黑树(red-black tree)数据结构实现, 按 key 排序.
    • LinkedHashMap 保持者插入顺序.
    • Hashtable 与HashMap实现方式一样,但Hashtable属于同步(synchronized)的.

      所以如果代码是线程安全的,那么应该使用HashMap,因为Hashtable的同步是有一定量的运行代价的。而现今对于需要同步的Map,使用 ConcurrentHashMap 也比 Hashtable 有更高的效率。

      注:map中的key和value都必须是Object(除非指定了泛型)

    1.2、Map接口和Collection接口的不同

      Map是双列的,Collection是单列的
      Map的键唯一,Collection的子体系Set是唯一的
      Map集合的数据结构值针对键有效,跟值无关;Collection集合的数据结构是针对元素有效。

      Map集合没有直接取出元素的方法,而是先转成Set集合,在通过迭代获取元素

    1.3、Map集合功能概述

    添加功能
            * V put(K key,V value):添加元素。
                * 如果键是第一次存储,就直接存储元素,返回null
                * 如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值
           putAll(Map<? extends K,? extends V> m)将指定Map中的键值对复制到Map中 删除功能
    * void clear():移除所有的键值对元素 * V remove(Object key):删除指定key所对应的键值对,返回可以所关联的value,如果key不存在,返回null 判断功能 * boolean containsKey(Object key):判断集合是否包含指定的键 * boolean containsValue(Object value):判断集合是否包含指定的值 * boolean isEmpty():判断集合是否为空 获取功能 * Set<Map.Entry<K,V>> entrySet(): * V get(Object key):根据键获取值 * Set<K> keySet():获取集合中所有键的集合 * Collection<V> values():获取集合中所有值的集合 长度功能 * int size():返回集合中的键值对的个数

      Map中包含一个内部类:Entry。该类封装了一个键值对,它包含了三个方法:

    Object getKey():返回该Entry里包含的key值。
    Object getValeu():返回该Entry里包含的value值。
    Object setValue(V value):设置该Entry里包含的value值,并返回新设置的value值。

    1.4、Map实例之遍历

      Map的遍历大体有3种:
        第一种:遍历Map.entrySet():它的每一个元素都是Map.Entry对象,这个对象中,放着的就是Map中的某一对key-value。
        第二种:遍历Map.keySet():它是Map中key值的集合,我们可以通过遍历这个集合来读取Map中的元素。
        第三种:遍历Map.values():它是Map中value的集合,我们可以直接通过这个集合遍历Map中的值,却不能读取key。

      1)Map集合的遍历之键找值

        思路:一是:获取所有键的集合。二是:遍历键的集合,获取到每一个键。三是:根据键找值。

    package com.zyh.Collection.map;
    
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Set;
    
    public class MapDemo_0010 {
    //    Map集合的遍历之键找值
        public static void main(String[] args) {
            Map<String,Integer> map = new HashMap<>();
            map.put("张三",34);
            map.put("美女",14);
            map.put("帅哥",24);
            map.put("流浪汉",74);
    
            /*方式一:使用迭代器
            Set<String> str = map.keySet();
            Iterator<String> it = str.iterator();
            while (it.hasNext()){
                String key = it.next();
                Integer value = map.get(key);
                System.out.println("key="+key+"——value="+value);
            }*/
    
            //方式二:使用增强for循环
            for (String key:map.keySet()){
                System.out.println("key="+key+"——value="+map.get(key));
            }
        }
    }
    MapDemo_0010

      2)Map集合的遍历之键值对对象找键和值

        思路:一是:获取所有键值对对象的集合。二是:遍历键值对对象的集合,获取到每一个键值对对象。三是:根据键值对对象找键和值。

    package com.zyh.Collection.map;
    
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Set;
    
    public class MapDemo_0011 {
        //Map集合的遍历之键值对对象找键和值
        public static void main(String[] args) {
            Map<String,Integer> map = new HashMap<>();
            map.put("张三",34);
            map.put("美女",14);
            map.put("帅哥",24);
            map.put("流浪汉",74);
    
            /*方式一:使用迭代器
            Set<Map.Entry<String, Integer>> entry = map.entrySet(); //获取所有的键值对象的集合
            Iterator<Map.Entry<String, Integer>> it = entry.iterator(); //获取迭代器
            while (it.hasNext()){
                Map.Entry<String, Integer> en = it.next();  //获取键值对对象
                String key = en.getKey();   //根据键值对对象获取键
                Integer value = en.getValue();  //根据键值对对象获取值
                System.out.println("key="+key+"——value="+value);
            }*/
            //方式二:使用增强for循环
            for (Map.Entry<String,Integer> en : map.entrySet()){
                String key = en.getKey();
                Integer value = en.getValue();
                System.out.println("key="+key+"——value="+value);
            }
    
        }
    }
    MapDemo_0011

    二、HashMap

    2.1、HashMap概述  

      HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。它存储的时候是无序的
      HashMap 继承于AbstractMap,实现了Map、Cloneable、java.io.Serializable接口。
      HashMap 的实现不是同步的,这意味着它不是线程安全的。它的key、value都可以为null。此外,HashMap中的映射不是有序的。

      在java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外。

        HashMap实际上是一个“链表的数组”的数据结构,每个元素存放链表头结点的数组,即数组和链表的结合体。

      

      HashMap注意事项:
        1)HashMap底层维护一个数组,我们向HashMap中所放置的对象实际上是存储在该数组当中。
        2)当向HashMap中put一对键值时,它会根据key的hashCode值计算出一个位置,该位置就是此对象准备往数组中存放的位置。

    2.2、实例:在HashMap中存储key为Student对象,value为String类型  

      1)当键是自定义类型时怎么保证唯一性:重写hashCode()和equals()方法,这样我们在存储的时候如果有重复的键,后面的会覆盖后面的。

    package com.zyh.Collection.map;
    
    import com.zyh.domain.Student;
    import java.util.HashMap;
    
    public class HashMapDemo_0010 {
        public static void main(String[] args) {
            HashMap<Student,String> hs = new HashMap<>();
            hs.put(new Student("张三",23),"上海");
            hs.put(new Student("张三",23),"上海");
            hs.put(new Student("李四",55),"深圳");
            hs.put(new Student("王五",78),"苏州");
            hs.put(new Student("赵六",89),"杭州");
    
            System.out.println(hs);
        }
    }

      这里的话就会输出:

        

        分析:首先输出的都是无序的,为什么直接输出map就会打印呢?因为底层重写了toString方法。

        

        查看之后它的父类重写了toString()方法

    2.3、HashMap的用法

      需求:统计字符串中每个字符出现的次数

        String str = "aaaabbbcccccccccc";
                char[] arr = str.toCharArray();                        //将字符串转换成字符数组
                HashMap<Character, Integer> hm = new HashMap<>();    //创建双列集合存储键和值
                
                for(char c : arr) {                                    //遍历字符数组
                    if(!hm.containsKey(c)) {                        //如果不包含这个键
                        hm.put(c, 1);                                //就将键和值为1添加
                    }else {                                            //如果包含这个键
                        hm.put(c, hm.get(c) + 1);                    //就将键和值再加1添加进来
                    }
                    
                    //hm.put(c, !hm.containsKey(c) ? 1 : hm.get(c) + 1);
                    Integer i = !hm.containsKey(c) ? hm.put(c, 1) : hm.put(c, hm.get(c) + 1);
                            }
                
                for (Character key : hm.keySet()) {                    //遍历双列集合
                    System.out.println(key + "=" + hm.get(key));
                }
    View Code

    2.4、LinkedHashMap

      特点:底层是链表实现的可以保证怎么存就怎么取

      实例:

    package com.zyh.Collection.map;
    
    import com.zyh.domain.Student;
    import java.util.LinkedHashMap;
    
    public class LinkedHashMapDemo_0010 {
        public static void main(String[] args) {
            LinkedHashMap<Student,String> lhs = new LinkedHashMap<>();
            lhs.put(new Student("张三",23),"上海");
            lhs.put(new Student("李四",55),"深圳");
            lhs.put(new Student("王五",78),"苏州");
            lhs.put(new Student("赵六",89),"杭州");
    
            System.out.println(lhs);
        }
    }

      结果:

          

    四、TreeMap

    4.1、TreeMap概述

      TreeMap底层是二叉树数据结构,线程不同步,可用于给Map集合中的键进行排序。

      注意:
        1)用作key的对象必须实现hashCode和equals方法。
        2)不能保证其中的键值对的顺序
        3)尽量不要使用可变对象作为它们的key值。

      SortedMap接口和TreeMap类的关系

        SortedMap接口是Map的子接口,其进一步提供对于键的排序功能。
        TreeMap类就是SortedMap接口的实现类。
        TreeMap可以对key值进行自然排序或者比较器排序,其用法和TreeSet是一致的。

    4.2、用例子来说明TreeMap排序问题

    package com.zyh.Collection.map;
    
    import com.zyh.domain.Student;
    import java.util.TreeMap;
    
    public class TreeMapDemo_0010 {
        public static void main(String[] args) {
            TreeMap<Student,String> tm = new TreeMap<>();
            tm.put(new Student("张三",23),"上海");
            tm.put(new Student("李四",18),"深圳");
            tm.put(new Student("王五",78),"苏州");
            tm.put(new Student("赵六",66),"杭州");
            System.out.println(tm);
        }
    }

      当我们执行的时候会出错:

        

      因为key是自定义对象不知道怎么排序,所以这里要实现Comparable接口,重写compareTo方法,或者给TreeMap的构造方法中声明一个比较器。

        方式一:实现Comparable接口,重写compareTo方法

          实现Comparable接口:

          

          重写compareTo方法:

          

          结果:按年龄排序

          

        方式二:给TreeMap的构造方法中声明一个比较器(测试前把前面Student中的删除掉)     

    package com.zyh.Collection.map;
    
    import com.zyh.domain.Student;
    import java.util.Comparator;
    import java.util.TreeMap;
    
    public class TreeMapDemo_0010 {
        public static void main(String[] args) {
            TreeMap<Student,String> tm = new TreeMap<>(new Comparator<Student>() {
                @Override
                public int compare(Student s1, Student s2) {
                    int num = s1.getAge()-s2.getAge();
                    //s1.getName().compareTo(s2.getName())这里的compareTo方法是String类中的方法
                    return num==0?s1.getName().compareTo(s2.getName()):num;
                }
            });
            tm.put(new Student("张三",23),"上海");
            tm.put(new Student("李四",18),"深圳");
            tm.put(new Student("王五",78),"苏州");
            tm.put(new Student("赵六",66),"杭州");
            System.out.println(tm);
        }
    }

     五、HashMap与HashTable的区别

    5.1、同步性

      Hashtable是同步的,这个类中的一些方法保证了Hashtable中的对象是线程安全的。而HashMap则是异步的,因此HashMap中的对象并不是线程安全的
      因为同步的要求会影响执行的效率,所以如果你不需要线程安全的集合那么使用HashMap是一个很好的选择,这样可以避免由于同步带来的不必要的性能开销,从而提高效率。

    5.2、值

      HashMap可以让你将空值作为一个表的条目的key或value,但是Hashtable是不能放入空值的。HashMap最多只有一个key值为null,但可以有无数多个value值为null

    5.3、性能

      HashMap的性能最好,HashTable的性能是最差(因为它是同步的)    

        

    觉得不错的点个“推荐”哦!!!

  • 相关阅读:
    活期存款利息的计算方法
    Arachni web扫描工具
    python 多进程——使用进程池,多进程消费的数据)是一个队列的时候,他会自动去队列里依次取数据
    TCP报文格式和三次握手——三次握手三个tcp包(header+data),此外,TCP 报文段中的数据部分是可选的,在一个连接建立和一个连接终止时,双方交换的报文段仅有 TCP 首部。
    https ddos检测——研究现状
    https ddos攻击——由于有了认证和加解密 后果更严重 看绿盟的产品目前对于https的ddos cc攻击需要基于内容做检测
    识别TLS加密恶意流量
    CC工具列表
    MAP 最大后验——利用经验数据获得对未观测量的点态估计
    MAPE 平均绝对百分误差
  • 原文地址:https://www.cnblogs.com/zhangyinhua/p/7538377.html
Copyright © 2011-2022 走看看