• Map接口和常用方法


    Map接口和常用方法

    Map接口实现类的特点[很实用]

    注意:
    这里讲的是JDK8的Map接口特点

    1. Map 与 Collection 并列存在。用于保存具有映射关系的数据: Key-Value

    2. Map 中的 key 和 value 可以是任何引用类型的数据,会封装到 HashMap$Node 对象中

    3. Map 中的 key 不允许重复,原因和 HashSet 一样,前面博文中分析过源码.

    4. Map 中的 value 可以重复

    5. Map 的 key 可以为 null , value 也可以为 null ,注意 key 为 null ,只能有一个,
      value为null ,可以多个.

    6. 常用 String 类作为 Map 的 key

    7. key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到对应的 value

      package www.xz.map_;

      import java.util.HashMap;
      import java.util.Map;

      /**

      • @author 许正

      • @version 1.0
        */
        @SuppressWarnings({“all”})
        public class Map_ {
        public static void main(String[] args) {
        //1) Map 与 Collection 并列存在。用于保存具有映射关系的数据: Key-Value
        //2) Map 中的 key 和 value 可以是任何引用类型的数据,会封装到 HashMap$Node 对象中
        //3) Map 中的 key 不允许重复,原因和 HashSet 一样,前面博文中分析过源码.
        //4) Map 中的 value 可以重复
        //5) Map 的 key 可以为 null , value 也可以为 null ,注意 key 为 null ,只能有一个,
        // value为null ,可以多个.
        //6) 常用 String 类作为 Map 的 key
        //7) key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到对应的 value
        Map map = new HashMap();
        map.put(“no1”, “许正”);//k-v
        map.put(“no2”, “张三丰”);//k-v
        map.put(“no1”, “张无忌”);//当有相同的k,就等价于替换。
        map.put(“no3”, “张无忌”);//k-v
        map.put(null, null);//等价于替换
        map.put(null, “abc”);//k-v
        map.put(“no4”, null);
        map.put(“no5”, null);
        map.put(1, “豪豪”);
        map.put(new Object(), “秋山帅豪”);

         //通过get() 方法,传入 key ,会返回相对应的 value
         System.out.println(map.get("no3"));
         System.out.println("map=" + map);
        
        • 1
        • 2
        • 3

        }
        }

    **8. Map存放数据的key-value示意图,一对k-v是放在一个HashMap$Node中的,
    因为Node实现了Entry 接口,有些书上也说一对k-v就是一个Entry(如图) **
    请添加图片描述

    请添加图片描述

    package www.xz.map_;
    
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;
    
    /**
     * @author 许正
     * @version 1.0
     */
    @SuppressWarnings({"all"})
    public class MapSource_ {
        public static void main(String[] args) {
    
            Map map = new HashMap();
            map.put("no1", "许正");//k-v
            map.put("no2", "张三丰");//k-v
    
            //1. k-v最后是HashMap$Node node = newNode (hash, key, vaLue, nuLl)
            //2. k-v为了方便程序员的遍历,还会创建EntrySet 集合,该集合存放的元素的类型Entry, 而一个Entry
            //   对象就有k,v EntrySet> 即: transient Set> entrySet ;
            //3. entrySet 中,定 义的类型是Map.Entry ,但是实际上存放的还是HashMap$Node
            //   这是因为 static class Node impLements Map。Entry
            //4. 当把 HashMap$Node 对象存放到entrySet 就方便我们的遍历
            Set set = map.entrySet();//HashMap$EntrySet
            System.out.println(set.getClass());
            for (Object obj : set) {
                //System.out.println(obj. getClass()); //HashMap$Node
                //为了从HashMap$Node 取出k-v
                //1. 先做一个向下转型
                Map.Entry entry = (Map.Entry) obj;
                System.out.println(entry.getKey() + "-" + entry.getValue());
            }
    
            Set keySet = map.keySet();
            System.out.println(keySet.getClass());
            Collection values = map.values();
            System.out.println(values.getClass());
            
    
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    Map接口常用方法

    1. put:添加

    2. remove:根据键删除映射关系

    3. get:根据键获取值

    4. size:获取元素个数

    5. isEmpty:判断个数是否为0

    6. clear:清除

    7. containsKey:查找键是否存在

      package www.xz.map_;

      import java.util.HashMap;
      import java.util.Map;

      /**

      • @author 许正

      • @version 1.0
        */
        @SuppressWarnings({“all”})
        public class MapMethod {
        public static void main(String[] args) {
        //演示Map接口的常用方法

         HashMap map = new HashMap();
         map.put("邓超", new Book("", 100));
         map.put("邓超", "孙丽");
         map.put("王宝强", "马蓉");
         map.put("宋喆", "马蓉");
         map.put("秋山帅豪", null);
         map.put(null, " 刘亦菲");
         map.put("鹿晗", " 关晓彤");
        
         System.out.println("map=" + map);
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10

      // 1) remove:根据键删除映射关系
      map.remove(null);
      System.out.println(“map” + map);
      // 2) get:根据键获取值
      Object o = map.get(“秋山帅豪”);
      System.out.println(“帅豪对应的对象:” + o);
      // 3) size:获取元素个数
      System.out.println(map.size());
      // 4) isEmpty:判断个数是否为0
      System.out.println(map.isEmpty());
      // 5) clear:清除
      map.clear();
      System.out.println(“map=” + map);
      // 6) containsKey:查找键是否存在
      System.out.println(map.containsKey(“秋山帅豪”));
      }
      }

      class Book {
      private String name;
      private int num;

      public Book(String name, int num) {
          this.name = name;
          this.num = num;
      }
      
      • 1
      • 2
      • 3
      • 4

      }

    Map接口遍历方法

    Map遍历的示意图(比List ,和Set复杂点,但是基本原理一样)

    请添加图片描述

    Map遍历方式案例演示

    1. containsKey:查找键是否存在

    2. keySet:获取所有的键

    3. entrySet:获取所有关系k-v

    4. values:获取所有的值

      package www.xz.map_;

      import java.util.*;

      /**

      • @author 许正

      • @version 1.0
        */
        @SuppressWarnings({“all”})
        public class MapFor {
        public static void main(String[] args) {
        HashMap map = new HashMap();
        map.put(“邓超”, new Book(“”, 100));
        map.put(“邓超”, “孙丽”);
        map.put(“王宝强”, “马蓉”);
        map.put(“宋喆”, “马蓉”);
        map.put(“秋山帅豪”, null);
        map.put(null, “刘亦菲”);
        map.put(“鹿晗”, “关晓彤”);

         //第一组:先取出所有的 Key ,通过Key 取出对应的Value
         Set keySet = map.keySet();
         //(1) 增强for
         System.out.println("===第一种方式===");
         for (Object key : keySet) {
             System.out.println(key + "-" + map.get(key));
         }
         //(2) 迭代器
         System.out.println("===第二种方式===");
         Iterator iterator = keySet.iterator();
         while (iterator.hasNext()) {
             Object next = iterator.next();
             System.out.println(next + "-" + map.get(next));
         }
        
         //第二组:把所有的Value 取出
         Collection values = map.values();
         //这里可以使用所有的ColLections使用的遍历方法
         System.out.println("---取出所有的Value 增强for---");
         for (Object value : values) {
             System.out.println(value);
         }
         System.out.println("---取出所有的Value 迭代器---");
         Iterator iterator2 = values.iterator();
         while (iterator2.hasNext()) {
             Object next = iterator2.next();
             System.out.println(next);
         }
        
         //第三组:通过EntrySet 来获取k-v
         Set entrySet = map.entrySet();
         System.out.println("---使用EntrySet的 增强for(第三种)---");
         for (Object o : entrySet) {
             Map.Entry entry = (Map.Entry) o;
             System.out.println(entry.getKey() + "-" + entry.getValue());
         }
         System.out.println("---使用EntrySet的 迭代器(第四种)---");
         Iterator iterator3 = entrySet.iterator();
         while (iterator3.hasNext()) {
             Object next = iterator3.next();
             Map.Entry next1 = (Map.Entry) next;
             System.out.println(next1.getKey() + "-" + next1.getValue());
         }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
        • 35
        • 36
        • 37
        • 38
        • 39
        • 40
        • 41
        • 42
        • 43

        }
        }

    MapExercise

    请添加图片描述

    package www.xz.map_;
    
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Set;
    
    /**
     * @author 许正
     * @version 1.0
     */
    @SuppressWarnings({"all"})
    public class MapExercise {
        public static void main(String[] args) {
            Map map = new HashMap();
            Employee jack = new Employee("jack", 19000, 1);
            Employee tom = new Employee("tom", 20000, 2);
            Employee marry = new Employee("marry", 15000, 3);
            map.put(jack.getId(), jack);
            map.put(tom.getId(), tom);
            map.put(marry.getId(), marry);
    
            Set set = map.keySet();
            System.out.println("遍历显示工资大于18000的员工:");
            for (Object o : set) {
                Object o1 = map.get(o);
                Employee o11 = (Employee) o1;
                if (o11.getSal() > 18000) {
                    System.out.println(o11);
                }
            }
    
            //2. 使用EntrySet ->迭代器
            System.out.println("使用EntrySet ->迭代器:");
            Set set1 = map.entrySet();
            Iterator iterator = set1.iterator();
            while (iterator.hasNext()) {
                Object next =  iterator.next();
                Map.Entry entry = (Map.Entry) next;
                Employee employee = (Employee) entry.getValue();
                if (employee.getSal()>18000){
    //                System.out.println(entry.getValue());
                    System.out.println(employee);
                }
            }
    
        }
    }
    
    class Employee {
        public String name;
        private double sal;
        private int id;
    
        public Employee(String name, double sal, int id) {
            this.name = name;
            this.sal = sal;
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public double getSal() {
            return sal;
        }
    
        public void setSal(double sal) {
            this.sal = sal;
        }
    
        public double getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        @Override
        public String toString() {
            return "Employee{" +
                    "name='" + name + ''' +
                    ", sal=" + sal +
                    ", id=" + id +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93

    HashMap小结

    1. Map接口的常用实现类: HashMap、Hashtable和Properties.
    2. HashMap是Map接口使用频率最高的实现类。
    3. HashMap是以key-val对的方式来存储数据[案例Entry]
    4. key不能重复,但是值可以重复,允许使用null键和null值。
    5. 如果添加相同的key ,则会覆盖原来的key-val等同于修改.(key不会替换,val会替换)
    6. 与HashSet一样,不保证映射的顺序,因为底层是以hash表的方式来存储的.
    7. HashMap没有实现同步,因此是线程不安全的

    HashMap底层机制及源码剖析

    示意图

    请添加图片描述

    1. (k,v)是一个Node实现了Map.Entry,查看HashMap的源码可以看到.
    2. jdk7.0的hashmap底层实现[数组+链表],jdk8.0底层[数组+链表+红黑树]

    扩容机制和[HashSet相同]

    1. HashMap底层维护了Node类型的数组table,默认为null
    2. 当创建对象时,将加载因子(loadfactor)初始化为0.75.
    3. 当添加key-val时,通过key的哈希值得到在table的索引。 然后判断该索引处是否有元素,
      如果没有元素直接添加。如果该索引处有元素,继续判断该元素的key是否和准备加入的
      key相等,如果相等,则直接替换val;如果不相等需要判断是树结构还是链表结构,做出
      相应处理。如果添加时发现容量不够则需要扩容。
    4. 第1次添加,则需要扩容table容量为16,临界值(threshold)为12.
    5. 以后再扩容,则需要扩容table容量为原来的2倍,临界值为原来的2倍,即24,依次类推.
    6. 在Java8中,如果一条链表的元素个数超过TREEIFY THRESHOLD(默认是8),并且
      table的大小>= MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树)

    追一下源码!!!

    package www.xz.map_;
    
    import java.util.HashMap;
    
    /**
     * @author 许正
     * @version 1.0
     */
    @SuppressWarnings({"all"})
    public class HashMapSource01 {
        public static void main(String[] args) {
            HashMap map = new HashMap();
            map.put("java", 10);//ok
            map.put("php", 10);//ok
            map.put("java", 20);//替换value
    
            System.out.println("map=" + map);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    HashMap扩容数化触发

    package www.xz.map_;
    
    import java.util.HashMap;
    import java.util.Objects;
    
    /**
     * @author 许正
     * @version 1.0
     */
    @SuppressWarnings({"all"})
    public class HashMapSource02 {
        public static void main(String[] args) {
            HashMap map = new HashMap();
            for (int i = 1; i <=12 ; i++) {
                map.put(new A(i),"hello");
            }
    
            System.out.println(map);
        }
    }
    
    class A{
        private int num;
    
        public A(int num) {
            this.num = num;
        }
    
        @Override
        public int hashCode() {
            return 100;
        }
    
        @Override
        public String toString() {
            return "
    A{" +
                    "num=" + num +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    Map接口实现类Hashtable

    HashTable的基本介绍

    1. 存放的元素是键值对:即K-V

    2. hashtable的键和值都不能为null,否则会抛出NullPointerException

    3. hashTable使用方法基本上和HashMap一样

    4. hashTable是线程安全的,hashMap是线程不安全的

    5. 简单看下底层结构

    //简单说明一下Hashtable的底层
    //1.底层有数组Hashtable$Entry[] 初始化大小为11
    //2.临界值threshold 8 = 11 * 0.75
    //3.扩容:按照自己的扩容机制来进行即可。
    //4.执行方法addEntry(hash, key, value, index); 添加K-V封装到Entry
    //5.当if (count >=threshold)满足时,就进行扩容
    //5.按照int newCapacity = (oldCapacity << 1) + 1;的大小扩容。

    HashTable的应用案例

    debug看一下table表是如何扩容的

    package www.xz.map_;
    
    import java.util.Hashtable;
    
    /**
     * @author 许正
     * @version 1.0
     */
    @SuppressWarnings({"all"})
    public class HashTableExercise {
        public static void main(String[] args) {
            Hashtable hashtable = new Hashtable();
            hashtable.put("john",100);
    //        hashtable.put(null,100);
    //        hashtable.put("john",null);
            hashtable.put("lucy",100);
            hashtable.put("lic",100);
            hashtable.put("lic",80);
    
            hashtable.put("hello1",1);
            hashtable.put("hello2",1);
            hashtable.put("hello3",1);
            hashtable.put("hello4",1);
            hashtable.put("hello5",1);
            hashtable.put("hello6",1);
    
            System.out.println(hashtable);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    Hashtable 和HashMap对比

    请添加图片描述

    Map接口实现类Properties

    基本介绍

    1. Properties类继承自Hashtable类并且实现了 Map接口,也是使用一种键值对的形
      式来保存数据。

    2. 他的使用特点和Hashtable类似

    3. Properties 还可以用于从xxx.properties文件中,加载数据到Properties类对象,
      并进行读取和修改

    4. 说明:工作后xxx.properties 文件通常作为配置文件,这个知识点在IO流举例,有兴
      趣可先看文章[点击跳转](https:/ /www.cnblogs.com/ xudong bupt/ p/3758136.html)

      package www.xz.map_;

      import java.util.Properties;

      /**

      • @author 许正

      • @version 1.0
        */
        @SuppressWarnings({“all”})
        public class Properties_ {
        public static void main(String[] args) {
        Properties properties = new Properties();
        //1. Properties 继承Hashtable
        //2. 可以通过k-v存放数据,当然key和value不能为null
        properties.put(“john”, 100);
        properties.put(“lucy”, 100);
        properties.put(“lic”, 100);
        properties.put(“lic”, 88);//替换

         //通过key 获取对应值
         System.out.println(properties.get("lic"));
        
         //删除
         properties.remove("lic");
         System.out.println(properties);
        
         //修改(直接覆盖)
         properties.put("john","jack");
         System.out.println(properties);
        
         //查找
         System.out.println(properties.getProperty("john"));
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13

        }
        }

    总结-开发中如何选择集合实现类

    在开发中,选择什么集合实现类,主要取决于业务操作特点,然后根据集合实现类特性进行
    选择,分析如下:

    1. 先判断存储的类型(一组对象或一组键值对)
    2. 一组对象: Collection接口
      允许重复: List
      增删多: LinkedList [底层维护了一个双向链表]
      改查多: ArrayList [底层维护Object类型的可变数组]
      不允许重复: Set
      无序: HashSet [底层是HashMap ,维护了一个哈希表即(数组+链表+红黑树)]
      排序: TreeSet
      插入和取出顺序一致: LinkedHashSet , 维护数组+双向链表
    3. 一组键值对: Map
      键无序: HashMap [底层是:哈希表jdk7: 数组+链表,jdk8: 数组+链表+红黑树]
      键排序: TreeMap
      键插入和取出顺序一致: LinkedHashMap
      读取文件Properties

    Map接口实现类TreeMap

    package www.xz.map_;
    
    import java.util.Comparator;
    import java.util.TreeMap;
    
    /**
     * @author 许正
     * @version 1.0
     */
    @SuppressWarnings({"all"})
    public class TreeMap_ {
        public static void main(String[] args) {
    //        TreeMap treeMap = new TreeMap();
            TreeMap treeMap = new TreeMap(new Comparator() {
                @Override
                public int compare(Object o1, Object o2) {
                    //按照首字母倒序
    //                return ((String)o2).compareTo((String)o1);
                    //按照字符串长度
                    return ((String)o1).length()-((String)o2).length();
                }
            });
            treeMap.put("jack", "杰克");
            treeMap.put("tom", "汤姆");
            treeMap.put("kristina", "克雷丝缇娜");
            treeMap.put("smith", "史密斯");
    
            System.out.println(treeMap);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
  • 相关阅读:
    WPF篇(8)- Button按钮
    vue3探索——vue3+vite2动态绑定图片优雅解决方案
    Android设计模式--Builder建造者模式
    Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (二)
    【GO语言基础】函数
    gdb常用调试命令
    Linux学习之make/Makefile
    (vue)Js 获取剪贴板值
    SHELL脚本编程----netstat练习2-查看和3306端口建立的连接
    PMP提分练习
  • 原文地址:https://blog.csdn.net/m0_67403272/article/details/126435008