Java---Map 接口

Map 的介绍

Map 是 Java 中用于存储键值对的集合接口,常见实现包括 HashMapTreeMapLinkedHashMap。它允许通过键快速查找对应的值。

Map 接口实现类的特点【很实用】

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

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

java 复制代码
package com.heima.Hello.Map_;

import java.util.HashMap;
import java.util.Map;
public class map_ {
    public static void main(String[] args) {
        // 1)Map 与 Collection 并列存在。用于保存具有映射关系的数据:Key-Value(双列元素)
        Map map = new HashMap();
        map.put("no1", "张无忌"); // k-v
        map.put("no2","张飞"); // k-v
        System.out.println("map = " + map);

    }
}

2)Map 中的 key 和 values 可以是任何引用类型的数据,会封装到 HashMap$Node 对象中,当有相同的 key ,就会替换掉原来的 value

3)Map中的 key 不允许重复,原因和 HashSet 一样

java 复制代码
package com.heima.Hello.Map_;

import java.util.HashMap;
import java.util.Map;
public class map_ {
    public static void main(String[] args) {
        Map map = new HashMap();
        map.put("no1", "张无忌"); // k-v
        map.put("no2","张飞"); // k-v
        map.put("no1","张三丰");
        System.out.println("map = " + map);

    }
}

4)Map 中的 value 可以重复

java 复制代码
package com.heima.Hello.Map_;

import java.util.HashMap;
import java.util.Map;
public class map_ {
    public static void main(String[] args) {
        Map map = new HashMap();
        map.put("no1", "张无忌"); // k-v
        map.put("no2","张飞"); // k-v
        map.put("no3","张无忌");
        System.out.println("map = " + map);
    }
}

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

java 复制代码
package com.heima.Hello.Map_;

import java.util.HashMap;
import java.util.Map;
public class map_ {
    public static void main(String[] args) {
        Map map = new HashMap();
        map.put(null,null);
        map.put(null,"你好");
        System.out.println("map = " + map);

    }
}

6)常用 String 类作为 Map 的 Key (常用的是 String 类,但也可以是其他类型, Object 的子类)

java 复制代码
package com.heima.Hello.Map_;

import java.util.HashMap;
import java.util.Map;
public class map_ {
    public static void main(String[] args) {
        Map map = new HashMap();
        map.put(1,"阳光");
        map.put(new Object(),"周芷若");
        System.out.println("map = " + map);

    }
}

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

java 复制代码
package com.heima.Hello.Map_;

import java.util.HashMap;
import java.util.Map;
public class map_ {
    public static void main(String[] args) {
        Map map = new HashMap();
        map.put(1,"阳光");
        map.put(new Object(),"周芷若");
        map.put("no1","金毛狮王");
        map.put(22.0,"小龙女");
        map.put("no2","abcd");
        System.out.println("map = " + map);

        // 通过 get 方法,传入 key,返回相应的 value
        System.out.println(map.get("no2"));

    }
}

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

java 复制代码
package com.heima.Hello.Map_;

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

public class map_ {
    public static void main(String[] args) {
        Map map = new HashMap();
        map.put("first", "贾宝玉");
        map.put("Second", "林黛玉");

        // 解读
        // 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 就方便我们的遍历
        // k getKey()  v getValue()
        Set set = map.entrySet();
        System.out.println(set.getClass()); // HashMap$Node
        for (Object obj : set) {
            // System.out.println(obj.getClass());
            // 为了从HashMap$Node 中取出 k-v
            // 1. 先做一个向下转型
            Map.Entry entry = (Map.Entry) obj;
            System.out.println(entry.getKey() + "-" + entry.getValue());
        }


    }
}

Map接口和常用方法

1)put 添加

java 复制代码
package com.heima.Hello.Map_;

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

public class MapMethod {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        Map map = new HashMap();

        map.put("水果","苹果");
        map.put("蔬菜","西兰花");
        map.put("蔬菜","萝卜");
        map.put(null,"书籍");

        System.out.println("map = " + map);
    }
}

2)remove 根据键删除映射关系

java 复制代码
package com.heima.Hello.Map_;

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

public class MapMethod {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        Map map = new HashMap();

        map.put("水果","苹果");
        map.put("蔬菜","西兰花");
        map.put("蔬菜","萝卜");
        map.put("交通工具","地铁");
        map.put(null,"书籍");

        System.out.println("map = " + map);

        map.remove(null);
        System.out.println("使用 remove 方法后的 map = " + map);
    }
    
}

3)get 根据键获取值

java 复制代码
package com.heima.Hello.Map_;

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

public class MapMethod {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        Map map = new HashMap();

        map.put("水果","苹果");
        map.put("蔬菜","西兰花");
        map.put("蔬菜","萝卜");
        map.put("交通工具","地铁");

        Object value = map.get("交通工具");
        System.out.println(value); //通过 key 得到 value
    }

}

4)size获取元素个数

java 复制代码
package com.heima.Hello.Map_;

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

public class MapMethod {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        Map map = new HashMap();

        map.put("水果","苹果");
        map.put("蔬菜","西兰花");
        map.put("蔬菜","萝卜");
        map.put("交通工具","地铁");

        System.out.println(map.size());
    }

}

5)isEmpty 判断个数是否为0

java 复制代码
package com.heima.Hello.Map_;

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

public class MapMethod {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        Map map = new HashMap();

        map.put("水果","苹果");
        map.put("蔬菜","西兰花");
        map.put("蔬菜","萝卜");
        map.put("交通工具","地铁");

        System.out.println(map.isEmpty());
    }

}

6)clear 清除

java 复制代码
package com.heima.Hello.Map_;

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

public class MapMethod {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        Map map = new HashMap();

        map.put("水果","苹果");
        map.put("蔬菜","西兰花");
        map.put("蔬菜","萝卜");
        map.put("交通工具","地铁");

        map.clear();
        System.out.println("map = " + map);
    }

}

7)containsKey 查找键是否存在

java 复制代码
package com.heima.Hello.Map_;

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

public class MapMethod {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        Map map = new HashMap();

        map.put("水果","苹果");
        map.put("蔬菜","西兰花");
        map.put("蔬菜","萝卜");
        map.put("交通工具","地铁");

        System.out.println(map.containsKey("蔬菜")); // 返回 true
    }

}

Map 遍历方式案例演示

1)containsKey 查找键是否存在

2)keySet 获取所有的键

java 复制代码
package com.heima.Hello.Map_;

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

public class MapMethod {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        Map map = new HashMap();

        map.put("水果","苹果");
        map.put("蔬菜","西兰花");
        map.put("蔬菜","萝卜");
        map.put("交通工具","地铁");
        map.put("糕点","吐司");

        System.out.println("map = " + map);

        // 先取出所有的 key,再通过 key 取出对应的 value
        Set key_set = map.keySet();
    }
}

3)entrySet 获取所有的键

4)values 获取所有的值

HashMap 底层机制及源码剖析

扩容机制 [ 和 HashSet 相同 ]

1)HashMap 底层维护了 Node 类型的数据 table,默认为 null

2)当创建对象时,将加载因子(loadfactor)初始化为 0.75

3)当添加 key-val 时,通过 key 的哈希值得到在 table 的索引。然后判断该索引是否有元素,如果没有元素直接添加。如果该索引处有元素,继续判断该元素的 key 和准备加入的 key 是否相等,如果相等,则直接替换 val ;如果不相等需要判断是树结构还是链表结构,做出相应处理。如果添加时发现容量不够,则需要扩容。

4)第一次添加,则需要扩容 table 容量为 16,临界值(threshold)为 12(16*0.75)

5)以后再扩容,则需要扩容 table 容量为原来的 2 倍(32),临界值为原来的 2 倍,即 24,依次类推。

6)在 Java 8 中,如果一条链表的元素个数超过 TREEIFY_THRESHOLD(默认是 8),并且 table 的大小 >= MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树)

总结---开发中如何中如何选择集合实现类(记住)

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

1)先判断存储的类型(一组对象[单列]或一组键值对 [双列] )

2)一组对象:Collection 接口

允许重复 :List

增删多:LinkedList [ 底层维护了一个双向链表 ]

改查多:ArrayList [ 底层维护 Object 类型的可变数组 ]

不允许重复:Set

无序:HashSet [ 底层是 HashMap,维护了一个哈希表,即(数组 + 链表 + 红黑树)]

排序:TreeSet

java 复制代码
package com.heima.Hello.Map_;

import java.util.Comparator;
import java.util.TreeSet;
@SuppressWarnings({"all"})
public class TreeSet_ {
    public static void main(String[] args) {

        // 解读
        //1. 当我们使用无参构造器,创建 TreeSet 时,仍然是无序的
        //2. 希望添加的元素,按照字符串大小来排序
        //3. 使用 TreeSet 提供一个构造器,可以传入一个比较器(原名内部类)
        //   并指定排序规则
        //4. 简单看看源码
        TreeSet treeSet = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                // 下面这句话是调用 String 类的 compare方法进行字符串比较
                return ((String) o1).compareTo((String) o2);
            }
        });
        treeSet.add("a");
        treeSet.add("tree");
        treeSet.add("hello");
        treeSet.add("world");
        System.out.println("treeset: " + treeSet);
    }
}

插入和取出顺序一致:LinkedHashSet。维护数组 + 双向链表

3)一组键值对:Map

键无序:HashMap [底层是:哈希表 jdk 7:数组 + 链表,jdk 8:数组 + 链表 + 红黑树]

键排序:TreeMap

键插入和取出顺序一致:LinkedHashMap

读取文件 Properties

相关推荐
qq_266348731 小时前
aspose处理模板,并去掉水印 jdk17
java·开发语言
繁华似锦respect1 小时前
C++ 设计模式之单例模式详细介绍
服务器·开发语言·c++·windows·visualstudio·单例模式·设计模式
小年糕是糕手1 小时前
【C++】类和对象(三) -- 拷贝构造函数、赋值运算符重载
开发语言·c++·程序人生·考研·github·个人开发·改行学it
f***24111 小时前
Spring Boot接收参数的19种方式
java·spring boot·后端
xunyan62341 小时前
面向对象(下)-设计模式与单例设计模式
java·单例模式·设计模式
杰克尼1 小时前
蓝桥云课-小蓝做题
java·数据结构·算法
艾莉丝努力练剑1 小时前
【C++:C++11收尾】解构C++可调用对象:从入门到精通,掌握function包装器与bind适配器包装器详解
java·开发语言·c++·人工智能·c++11·右值引用
卿雪1 小时前
MySQL【索引】篇:索引的分类、B+树、创建索引的原则、索引失效的情况...
java·开发语言·数据结构·数据库·b树·mysql·golang