Map接口和常用方法_程序员正正的博客-程序员宝宝_map接口

技术标签: spring  java  restful  Java基础  

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);
    }
}

**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<Entry<K,V>> 即: transient Set<Map。Entry<K,V>> entrySet ;
        //3. entrySet 中,定 义的类型是Map.Entry ,但是实际上存放的还是HashMap$Node
        //   这是因为 static class Node<K, V> impLements Map。Entry<K, V>
        //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());
        


    }
}

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) 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;
    }
}

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());
        }
    }
}

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 +
                '}';
    }
}

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<K,V>,查看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);
    }
}

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 "\nA{" +
                "num=" + num +
                '}';
    }
}

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);
    }
}

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. 一组对象: 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);
    }
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/WXxz0/article/details/120797873

智能推荐

【最详细】数据结构(C语言版 第2版)第四章课后习题答案 严蔚敏 等 编著_来老铁干了这碗代码的博客-程序员宝宝_数据结构c语言版严蔚敏课后答案

第 4 章串、数组和广义表1.选择题( 1)串是一种特殊的线性表,其特殊性体现在() 。A .可以顺序存储 B .数据元素是一个字符C.可以链式存储 D .数据元素可以是多个字符若答案: B( 2)串下面关于串的的叙述中, ()是不正确的?A.串是字符的有限序列 B.空串是由空格构成的串C.模式匹配是串的一种重要运算 D .串既可以采用顺序存储,也可以采用链式存储答案: B解释:空格常常是串的字符集合中的一个元素,有一个或多个空格组成的串成为空格串,零个字符的串成为空串,其长度为零。

python3.7安装opencv库_python 3.7.4 安装 opencv_nana 不是banana的博客-程序员宝宝

明确一下,我们需要使用python来调用opencv中的库函数,所以需要安装opencv-python。主要需要安装:1. opencv-python2. numpy第一步先来安装opencv-python。方法一:可以直接在cmd中使用pip install opencv-python我遇到了以下的问题(找不到一个满足当前python版本的opencv版本),如果你也是,那么使用下面的另一种方法...

mopatch oracle_[转]OPatch给Oracle打补丁 (写的太完美了),忍不住转了_瓖嘉的博客-程序员宝宝

任何软件都会存在这样或者那样的缺陷、Bug,Oracle也不例外。对于生产运维人员来说,定期升级系统、打补丁是日常工作中不可缺少的部分。相对于过去的版本,Oracle打补丁的方式已经变得比较简单,处理PSU的方法也发生了一些变化。在11g中,对于一些小bug的修复,我们可以使用OPatch工具进行补丁修复。对于大的版本升级,Oracle的PSU实际上就是一系列全新的安装文件,从MOS上下载之后就可...

算法期末考试复习题_时光荒凉了来时路的博客-程序员宝宝

算法期末考试复习题XD的小伙伴们很适合哦program 11、归并排序在最差最好平均情况下的时间复杂度分别是多少?答案:nlgn nlgn2、(判断) 归并排序的空间复杂度是O(1)? (判断)答案:false 应该是 O(n)3、优先队列提取最大元素的算法时间复杂度?(用O表示)答案:O(lgn)4、堆排序在最差最好平均情况下的时间复杂度分别是多少?答案:答案有争论,都是O(nlgn),最好达到O(n)5、(判断)堆排序的空间复杂度是O(1) ?答案:true6、请写出

在Vue项目中使用富文本编辑器vue-quill-editor_龙易安的博客-程序员宝宝

1、首先安装npm install vue-quill-editor --save2、可以注册为全局可用的组件import VueQuillEditor from 'vue-quill-editor'import 'quill/dist/quill.core.css'import 'quill/dist/quill.snow.css'import 'quill/dist/quill.bubble.css' Vue.use(VueQuillEditor, /* { default globa

PTA 6-3 逆序数据建立链表 (20分)_天上飞的云传奇的博客-程序员宝宝_6-3 逆序数据建立链表

PTA逆序数据建立链表本题要求实现一个函数,按输入数据的逆序建立一个链表。**函数接口定义:**struct ListNode *createlist();要求函数createlist利用scanf从输入中获取一系列正整数,当读到−1时表示输入结束。按输入数据的逆序建立一个链表,并返回链表头指针。链表节点结构定义如下:struct ListNode { int data; ...

随便推点

vue脚手架项目接入百度统计PV UV_yanghouqing的博客-程序员宝宝

vue脚手架接入百度统计实现PV UV展示实战 简单清晰

完全背包选硬币hdu2069_夜雨声訉的博客-程序员宝宝

Coin Change Problem Description Suppose there are 5 types of coins: 50-cent, 25-cent, 10-cent, 5-cent, and 1-cent. We want to make changes with these coins for a given amount of money. For...

【Haskell】Haskell学习笔记 基础知识总结(持续更新!)_memcpy0的博客-程序员宝宝

文章目录0. 简介和准备1. 基础语法函数列表列表拼接 `++`列表取值 `!!`列表比较列表常用函数0. 简介和准备Haskell是一门声明式、函数式的编程语言,相比起命令式编程,它的代码相当简洁、表达力强。一个示例是Haskell写的八皇后:safe :: Int -&gt; [Int] -&gt; Int -&gt; Boolsafe _ [] _ = Truesafe x (x1:xs) n = x /= x1 &amp;&amp; x /= x1 + n &amp;&amp; x /=

python 线程池_python线程池threadpool实现篇_weixin_39952937的博客-程序员宝宝

本文为大家分享了threadpool线程池中所有的操作,供大家参考,具体内容如下首先介绍一下自己使用到的名词:工作线程(worker):创建线程池时,按照指定的线程数量,创建工作线程,等待从任务队列中get任务;任务(requests):即工作线程处理的任务,任务可能成千上万个,但是工作线程只有少数。任务通过 makeRequests来创建任务队列(request_queue):...

HDOJ题目2122Ice_cream’s world III(最小生成树)_Jogging_Clown的博客-程序员宝宝

Ice_cream’s world IIITime Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 800    Accepted Submission(s): 272Problem Descriptionice_cream’