Java集合框架——Map接口

第三阶段 JAVA常见对象的学习

集合框架——Map集合

image

在实际需求中,我们常常会遇到这样的问题,在诸多的数据中,通过其编号来寻找某一些信息,从而进行查看或者修改,例如通过学号查询学生信息。今天我们所介绍的Map集合就可以很好的帮助我们实现这种需求

(一) 概述及功能

(1) 概述

Map是一种存储元素对的集合(元素对分别称作 键 和 值 也称键值对)它将键映射到值的对象。一个映射不能包含重复的键,并且每个键最 多只能映射到一个值。

怎么理解呢?

键 (key):就是你存的值的编号 值 (value):就是你要存放的数据

你可以近似的将键理解为下标,值依据键而存储,每个键都有其对应值。这两者是1、1对应的

但在之前下标是整数,但是Map中键可以使任意类型的对象。

Map集合和Collection集合的区别?

  • Map集合存储元素是成对出现的,Map集合的键是唯一的,值是可重复的
  • Collection集合存储元素是单独出现的,Collection的子类Set是唯一的,List是可重复的。
  • Map集合的数据结构值针对键有效,跟值无关,Collection集合的数据结构是针对元素有效

(2) 功能

A:添加功能

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

B:删除功能

//移除所有的键值对元素
void clear()

//根据键删除键值对元素,并把值返回
V remove(Object key)

C:判断功能

//判断集合是否包含指定的键
boolean containsKey(Object key)

//判断集合是否包含指定的值
boolean containsValue(Object value)

//判断集合是否为空
boolean isEmpty()

D:获取功能

//将map集合中的键和值映射关系打包为一个对象
Set<Map.Entry<K,V>> entrySet()

//根据键获取值
V get(Object key)

//获取集合中所有键的集合
Set<K> keySet()

//获取集合中所有值的集合
Collection<V> values()

E:长度功能

//返回集合中的键值对的对数
int size()

(二) Map集合的遍历

package cn.bwh_01_iterator;

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

public class MapDemo {
    public static void main(String[] args) {
        Map<String, String> hm = new HashMap<String, String>();
        hm.put("bwh002", "i");
        hm.put("bwh001", "love");
        hm.put("bwh003", "you");

        //方式一 键找值
        Set<String> set = hm.keySet();

        //迭代器遍历
        Iterator<String> it = set.iterator();
        while (it.hasNext()) {
            String key = it.next();
            String value = hm.get(key);
            System.out.println(key + "---" + value);
        }

        //增强for遍历
        for (String key : set) {
            String value = hm.get(key);
            System.out.println(key + "---" + value);
        }

        //方式二 键值对对象找键和值(推荐)
        Set<Map.Entry<String, String>> set2 = hm.entrySet();

        //迭代器遍历
        Iterator<Map.Entry<String, String>> it2 = set2.iterator();
        while (it2.hasNext()) {
            //返回的是封装了key和value对象的Map.Entry对象
            Map.Entry<String, String> entry = it2.next();
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + "---" + value);

        }

        //增强for遍历
        for (Map.Entry<String, String> me : set2) {
            String key = me.getKey();
            String value = me.getValue();
            System.out.println(key + "---" + value);
        }
    }
}

(三) Map及子类总结

Map(双列集合)

  • Map集合的数据结构仅仅针对键有效,与值无关。

  • 存储的是键值对形式的元素,键唯一,值可重复

HashMap

  • 底层数据结构是哈希表,线程不安全,效率高

  • 哈希表依赖两个方法:hashCod()和equals()

  • 执行顺序:

    • 首先判断hashCode()值是否相同
      • 是:继续执行equals(),看其返回值
        • 是true:说明元素重复,不添加
        • 是false:就直接添加到集合
      • 否:就直接添加到集合
  • 最终:

  • 自动生成hashCode()和equals()即可

LinkeHashMap

  • 底层数据结构是由链表和哈希表组成

  • 由链表保证元素有序

  • 由哈希表保证元素唯一

Hashtable

  • 底层数据结构是哈希表
  • 哈希表依赖两个......自动生成hashCode()和equals()即可

TreeMap

  • 底层数据结构是红黑树(是一种自平衡的二叉树)

如何保证元素唯一性呢?

  • 根据比较的返回值是否是0来决定

如何保证两种元素的排序呢?

  • 自然排序(元素具备比较性)
    • 让元素所属的类实现comparable接口
  • 比较器排序(集合具备比较性)
    • 让集合接收一个comparator的实现类对象

可以多层嵌套

HashMap集合嵌套HashMap

HashMap集合嵌套ArrayList

ArrayList集合嵌套HashMap

HashMap<String, ArrayList<String>> hm = new HashMap<String, ArrayList<String>>

1:Hashtable和HashMap的区别?

**Hashtable**:线程安全,效率低。不允许null键和null值

**HashMap**:线程不安全,效率高。允许null键和null值

(其实HashMap就是用来替代Hashtable的,就像ArrayList替代vector一样)

2:List,Set,Map等接口是否都继承子Map接口?

List,Set不是继承自Map接口,它们继承自Collection接口

Map接口本身就是一个顶层接口

需要排序:TreeMap

不需要排序:HashMap

不知道具体需求:HashMap

(四) 经典案例

(1) 统计字符串中字符出现的次数

import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeMap;

/*
 * 案例(统计字符串中字符出现的次数)
 * 需求:
 *      获取一个字符串出现的次数
 * 分析:
 *      A:定义一个字符串(或者键盘录入)
 *      B: 定义一个TreeMap集合
 *              键:Character
 *              值:Integer
 *      C:把字符串转换为字符数组
 *      D: 遍历字符数组,得到每一个字符
 *      E: 拿刚才得到的字符作为键去集合中找,看返回值
 *              是 null:说明该键不存在,就把该字符串作为键,1作为值去存储
 *              不是 null:说明该键存在,就把值加 1 然后重写存储该键和值
 *      F: 定义字符串缓冲区变量
 *      G:遍历集合,得到该建和值,按照要求拼接
 *      H:最后把字符串缓冲区转换为字符串输出
 */
 
public class CountDemo {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入需要统计的数据");
        String line = sc.nextLine();

        Map<Character, Integer> tm = new TreeMap<Character, Integer>();
        char[] chs = line.toCharArray();
        for (char ch : chs) {
            Integer i = tm.get(ch);
            if (i == null) {
                tm.put(ch, 1);
            } else {
                i++;
                tm.put(ch, i);
            }
        }

        StringBuilder s = new StringBuilder();
        Set<Character> set = tm.keySet();
        for (Character key : set) {
            Integer value = tm.get(key);
            s.append(key).append("(").append(value).append(")" + " ");
        }
        String result = s.toString();
        System.out.println("result: " + result);
    }
}

//运行结果
请输入需要统计的数据
HelloWorld
result: H(1) W(1) d(1) e(1) l(3) o(2) r(1) 

(2) 模拟斗地主案例

在讲解这个案例之前,我们先来了解一个我们下面案例中所需要知道的知识点

Collections 工具类

Collections:是针对集合进行操作的工具类,都是静态方法。

面试题:

Collection和Collections的区别?

Collection:是单列集合的顶层接口,有子接口List和Set。(Map是双列的)

Collections:是针对集合操作的工具类,有对集合进行排序和二分查找的方法

Collections的静态方法

//排序 默认情况下是自然顺序。
public static <T> void sort(List<T> list)

//二分查找
public static <T> int binarySearch(List<?> list,T key)

//最大值
public static <T> T max(Collection<?> coll)

//反转(逆序排序)
public static void reverse(List<?> list)

//随机置换(犹如洗牌,每次运行结果不一样)
public static void shuffle(List<?> list)

如果同时有自然排序和比较器排序,以比较器排序为主(也就是说,当同时实现了Student类的自然排序(implements Comparable<Student>)以及比较器排序的话(new Comparator<Student>()),比较器排序会覆盖自然排序)
//斗地主案例代码
package cn.bwh_03_PokerGame;

import java.util.*;

public class PokerGame {
    public static void main(String[] args) {
        HashMap<Integer, String> hm = new HashMap<Integer, String>();
        ArrayList<Integer> array = new ArrayList<Integer>();

        String[] colors = {"♥", "♠", "♣", "♦"};
        String[] numbers = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};

        int index = 0;
        for (String number : numbers) {
            for (String color : colors) {
                String poker = color.concat(number);
                hm.put(index, poker);
                array.add(index);
                index++;
            }
        }

        hm.put(index, "小王");
        array.add(index);
        index++;
        hm.put(index, "大王");
        array.add(index);
        index++;

        //洗牌
        Collections.shuffle(array);

        //发牌(发的是编号,为了保证编号是排序的,使用TreeSet接收)
        TreeSet<Integer> player1 = new TreeSet<Integer>();
        TreeSet<Integer> player2 = new TreeSet<Integer>();
        TreeSet<Integer> player3 = new TreeSet<Integer>();
        TreeSet<Integer> handcards = new TreeSet<Integer>();

        for (int x = 0; x < array.size(); x++) {
            if (x >= array.size() - 3) {
                handcards.add(array.get(x));
            } else if (x % 3 == 0) {
                player1.add(array.get(x));
            } else if (x % 3 == 1) {
                player2.add(array.get(x));
            } else if (x % 3 == 2) {
                player3.add(array.get(x));
            }
        }

        System.out.println("---------------------欢乐斗地主----------------------");
        //看牌(遍历TreeSet集合,获取编号,到HashMap集合找对应的牌)
        lookpocker("player1", player1, hm);
        lookpocker("player2", player2, hm);
        lookpocker("player3", player3, hm);
        lookpocker("预留", handcards, hm);
    }

    //看牌功能实现
    public static void lookpocker(String name, TreeSet<Integer> ts, HashMap<Integer, String> hm) {
        System.out.println(name + "的牌是:");
        for (Integer key : ts) {
            String value = hm.get(key);
            System.out.print(value + " ");
        }
        System.out.println();
    }
}

结尾:

如果内容中有什么不足,或者错误的地方,欢迎大家给我留言提出意见, 蟹蟹大家 !_

如果能帮到你的话,那就来关注我吧!(系列文章均会在公众号第一时间更新)

在这里的我们素不相识,却都在为了自己的梦而努力 ❤

一个坚持推送原创Java技术的公众号:理想二旬不止

image
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容

  • 四、集合框架 1:String类:字符串(重点) (1)多个字符组成的一个序列,叫字符串。生活中很多数据的描述都采...
    佘大将军阅读 742评论 0 2
  • 集合类框架的介绍: ![Java 集合类框架](https://upload-images.jianshu.io/...
    LynnGuo阅读 753评论 0 1
  • Collection ├List │├LinkedList │├ArrayList │└Vector │└Stac...
    AndyZX阅读 871评论 0 1
  • Map 接口简介 对于 Map 接口,Java的官方文档是这样介绍的: A Map is an object th...
    6ea566508d0d阅读 342评论 0 0
  • 概述 Java集合框架由Java类库的一系列接口、抽象类以及具体实现类组成。我们这里所说的集合就是把一组对象组织到...
    absfree阅读 1,251评论 0 10