week07_day06_Map

Map接口概述:

将键映射到值的对象。(我们可以根据键快速地查找到值)
Map 中键是唯一的 (不能包含重复的键)
每个键最多只能映射到一个值。

关于映射:
在这里插入图片描述
Map接口API:
在这里插入图片描述

  • V put(K key, V value)
    将指定的值与此映射中的指定键关联(可选操作)。如果此映射以前包含一个该键的映射关系,则用指定值替换旧值(当且仅当 m.containsKey(k) 返回 true 时,才能说映射 m 包含键 k 的映射关系)。
    返回以前与 key 关联的值,如果没有针对 key 的映射关系,则返回 null。(如果该实现支持 null 值,则返回 null 也可能表示此映射以前将 null 与 key 关联)。
  • void putAll(Map<? extends K,? extends V> m)
    从指定映射中将所有映射关系复制到此映射中(可选操作)。
    如果key已经存在就会更新value,key不存在就会添加进去。
  • V remove(Object key)
    如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。
    返回此映射中以前关联该键的值,如果此映射不包含该键的映射关系,则返回 null。

key对应的value可以为null,所以不能通过get(key) != null来判断key是否存在,应当通过containsKey(Object key) 来判断。

  • Set<Map.Entry<K,V>> entrySet()
    返回此映射中包含的映射关系的 Set 视图。
    关于Map.Entry<K,V>,是Map接口的内部接口:
    在这里插入图片描述
    ····················································································································································································································

HashMap概述:
基于哈希表的Map接口实现。
允许null键和null值。
不保证映射的顺序,特别是它不保证该顺序恒久不变。
不同步。

HashMap和HashSet的构造方法一样:
在这里插入图片描述

HashMap是基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。(除了非同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。

HashMap VS Hashtable
相同点:
底层的数据结构都是哈希表
不同点:
a. HashMap是不同步的, Hashtable是同步的
b. HashMap可以允许null键和null值,Hashtable不允许null键和null值
····················································································································································································································

LinkedHashMap概述:
HashMap的子类
Map 接口的哈希表和链表实现,具有可预知的迭代顺序.
链表定义了迭代顺序,该迭代顺序就是键值对的插入顺序。
不同步。

LinkedHashMap是Map 接口的哈希表和链接列表实现,具有可预知的迭代顺序。此实现与 HashMap 的不同之处在于,后者维护着一个运行于所有键值对的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序)。注意,如果在映射中重新插入 键,则插入顺序不受影响。(如果在调用 m.put(k, v) 前 m.containsKey(k) 返回了 true,则调用时会将键 k 重新插入到映射 m 中。)

为什么要注意这一点呢?
在week06_day02中讲过LRU算法,
在这里插入图片描述
改进:能不能够在O(1)的时间复杂度内完成所有操作?
LRU:哈希表+双向链表
但LRU应当将最近使用的结点删除,然后重新插入到head位置,而LinkedHashMap仅仅只是改变结点的value值,并不会改变结点的位置,所以,不能直接使用LinkedHashMap当做LRU的缓存。

····················································································································································································································

TreeMap概述:
底层的数据结构是红黑树。
如果创建对象时,没有传入 Comparator 对象,键将按自然顺序进行排序。
如果创建对象时,传入了 Comparator 对象,键将按 Comparator 进行排序。
不同步。

和TreeSet一样,我们将它的两个构造方法

  • TreeMap()
    使用键的自然顺序构造一个新的、空的树映射。
  • TreeMap(Comparator<? super K> comparator)
    构造一个新的、空的树映射,该映射根据给定比较器进行排序。

····················································································································································································································

练习:存储自定义对象

代码一:String类为key,Student类为value

Student类:

public class Student01 {
    private String name;
    private int age;

    public Student01() {
    }

    public Student01(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "Student01{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

}

测试类:

public class TreeMapDemo1 {

    public static void main(String[] args) {
        TreeMap<String, Student01> map = new TreeMap<>();
        Student01 s1 = new Student01("Allen", 22);
        Student01 s2 = new Student01("Beyonce", 23);
        Student01 s3 = new Student01("Catalina", 24);
        Student01 s4 = new Student01("Diana", 25);

        map.put("Allen",s1);
        map.put("Beyonce",s2);
        map.put("Catalina",s3);
        map.put("Diana",s4);

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

之前写TreeSet的代码时,会发现不在Student类中写implements Comparable的话就没法存入TreeSet,但是现在却存入了,为啥?
因为TreeSet的add方法存入的是TreeMap的key,key必须唯一,可比较,但是现在的代码中,key存的是String,String本身就实现了Comparable接口,而Student是value,value可以相同,也就不需要实现Comparable接口。

····················································································································································································································

代码二:
Student类:

public class Student02 implements Comparable<Student02> {
    private String name;
    private int age;

    public Student02() {
    }

    public Student02(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "Student01{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Student02 s) {
        int cmp = this.age - s.age;
        cmp = cmp != 0 ? cmp : this.name.compareTo(s.name);
        return cmp;
    }
}

测试类:

public class TreeMapDemo02 {

    public static void main(String[] args) {
        Map<Student02, String> map = new TreeMap<>();
        Student02 s1 = new Student02("Allen", 22);
        Student02 s2 = new Student02("Beyonce", 23);
        Student02 s3 = new Student02("Catalina", 24);
        Student02 s4 = new Student02("Diana", 25);

        map.put(s1, "Allen");
        map.put(s2, "Beyonce");
        map.put(s3, "Catalina");
        map.put(s4, "Diana");

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

····················································································································································································································

代码三:
Student类同代码一
测试类:

public class TreeMapDemo03 {

    public static void main(String[] args) {
        Map<Student01, String> map = new TreeMap<>(new Comparator<Student01>() {
            @Override
            public int compare(Student01 s1, Student01 s2) {
                int cmp = s1.getAge() - s2.getAge();
                cmp = cmp != 0 ? cmp : s1.getName().compareTo(s2.getName());
                return cmp;
            }
        });
        Student01 s1 = new Student01("Allen", 22);
        Student01 s2 = new Student01("Beyonce", 23);
        Student01 s3 = new Student01("Catalina", 24);
        Student01 s4 = new Student01("Diana", 25);

        map.put(s1, "Allen");
        map.put(s2, "Beyonce");
        map.put(s3, "Catalina");
        map.put(s4, "Diana");

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

····················································································································································································································

TreeMap特有的API:

  • K ceilingKey(K key)
    返回大于等于给定键的最小键;如果不存在这样的键,则返回 null。

  • K floorKey(K key)
    返回小于等于给定键的最大键;如果不存在这样的键,则返回 null。

  • K higherKey(K key)
    返回严格大于给定键的最小键;如果不存在这样的键,则返回 null。

  • K lowerKey(K key)
    返回严格小于给定键的最大键;如果不存在这样的键,则返回 null。

  • K firstKey()
    返回此映射中当前第一个(最低)键。

  • K lastKey()
    返回映射中当前最后一个(最高)键

  • Map.Entry<K,V> pollFirstEntry()
    移除并返回与此映射中的最小键关联的键-值映射关系;如果映射为空,则返回 null。

  • Map.Entry<K,V> pollLastEntry()
    移除并返回与此映射中的最大键关联的键-值映射关系;如果映射为空,则返回 null。

  • NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive)
    返回此映射的部分视图,其键的范围从 fromKey 到 toKey。

代码演示

public class TreeMapDemo04 {

    public static void main(String[] args) {
        TreeMap<Character, String> map = new TreeMap<>();
        map.put('A', "Allen");
        map.put('B', "Beyonce");
        map.put('C', "Catalina");
        map.put('D', "Diana");
        map.put('F', "Frances");
        map.put('X', "Xenia");

        // K ceilingKey(K key)
        /*System.out.println(map.ceilingKey('C')); // 'C'
        System.out.println(map.ceilingKey('E')); // 'F'
        System.out.println(map.ceilingKey('Z')); // null*/
        // K floorKey(K key)
        /*System.out.println(map.floorKey('C')); // C
        System.out.println(map.floorKey('E')); // D
        System.out.println(map.floorKey('0')); // null*/

        //    K higherKey(K key)
        /*System.out.println(map.higherKey('C')); // 'D'
        System.out.println(map.higherKey('E')); // 'F'
        System.out.println(map.higherKey('Z')); // null*/

        // K lowerKey(K key)
       /* System.out.println(map.lowerKey('C')); // B
        System.out.println(map.lowerKey('E')); // D
        System.out.println(map.lowerKey('0')); // null*/

        // K firstKey()
       /* System.out.println(map.firstKey());
        System.out.println(map);*/
        // K lastKey()
        /*System.out.println(map.lastKey());
        System.out.println(map);*/

        // Map.Entry<K,V> pollFirstEntry()
        /*System.out.println(map.pollFirstEntry());
        System.out.println(map);*/
        // Map.Entry<K,V> pollLastEntry()
        /*System.out.println(map.pollLastEntry());
        System.out.println(map);*/

        // 视图技术
        // NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive)
        NavigableMap<Character, String> subMap = map.subMap('C', true, 'X', false);
        System.out.println(subMap);
        subMap.pollFirstEntry();
        System.out.println(subMap);
        System.out.println(map);
    }
}

····················································································································································································································

Properties概述:
Hashtable<Object, Object> 的子类
Properties 类表示了一个可持久的属性集。
Properties 可保存在流中或从流中加载。
Properties 中每个键及其对应值都是一个字符串(Sring类型)

注意事项:不要使用Hashtable里面定义的方法添加键值对!因为它们可以插入不是String 类型的数据。
如果一个Properties中含有非String的键值对,那么这样的Properties是”不安全”的。调用 store 或者 save 方法将失败。

在这里插入图片描述

构造方法:

  • Properties()
    创建一个无默认值的空属性列表。
  • Properties(Properties defaults)
    创建一个带有指定默认值的空属性列表。

API:

  • String getProperty(String key)
    用指定的键在此属性列表中搜索属性。
  • String getProperty(String key, String defaultValue)
    用指定的键在属性列表中搜索属性。
    key存在的话返回对应的value,不存在的话返回defaultValue
  • Object setProperty(String key, String value)
    调用 Hashtable 的方法 put。
  • Set<String> stringPropertyNames()
    返回此属性列表中的键集,其中该键及其对应值是字符串,如果在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键。
public class PropertiesDemo1 {

    public static void main(String[] args) {
        Properties info = new Properties();
        info.setProperty("刘强东", "章泽天");
        info.setProperty("文章", "马伊利");
        info.setProperty("贾乃亮", "李小璐");
        info.setProperty("罗志祥", "周扬青");
        // System.out.println(info);

        /*Properties properties = new Properties(info);
        System.out.println(properties);
        System.out.println(properties.size());*/

        /*System.out.println(properties.containsKey("刘强东"));
        System.out.println(properties.getProperty("刘强东"));
        System.out.println(properties.getProperty("文章"));
        System.out.println(properties.getProperty("谢霆锋"));*/

        /*properties.setProperty("文章", "");
        System.out.println(properties.getProperty("文章"));*/

        // String getProperty(String key)
        /*System.out.println(info.getProperty("刘强东"));
        System.out.println(info.getProperty("谢霆锋"));

        // String getProperty(String key, String defaultValue)
        System.out.println(info.getProperty("刘强东", "default"));
        System.out.println(info.getProperty("谢霆锋", "default"));*/

        Set<String> names = info.stringPropertyNames();
        for(String key : names) {
            String value = info.getProperty(key);
            System.out.println(key + "=" + value);
        }
    }
}

····················································································································································································································

  • void load(InputStream inStream)
    从输入流中读取属性列表(键和元素对)。
  • void load(Reader reader)
    按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。
  • void loadFromXML(InputStream in)
    将指定输入流中由 XML 文档所表示的所有属性加载到此属性表中。
  • void store(OutputStream out, String comments)
    以适合使用 load(InputStream) 方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流。
  • void store(Writer writer, String comments)
    以适合使用 load(Reader) 方法的格式,将此 Properties 表中的属性列表(键和元素对)写入输出字符。
  • void storeToXML(OutputStream os, String comment)
    发出一个表示此表中包含的所有属性的 XML 文档。
  • void storeToXML(OutputStream os, String comment, String encoding)
    使用指定的编码发出一个表示此表中包含的所有属性的 XML 文档。
package com.cskaoyan.map;

import java.io.*;
import java.util.Properties;

/*
和流相关的API
    // void store(OutputStream out, String comments)
    void store(Writer out, String comments)
    // void load(InputStream inStream)
    void load(Reader read)
    注意事项:字节流默认使用 ISO 8859-1 字符编码(无法表示汉字),所以不建议使用第一个和第三个API。

    void storeToXML(OutputStream os, String comment)
    void loadFromXML(InputStream in)
    注意事项:默认采用UTF-8编码。
 */
public class PropertiesDemo2 {

    public static void main(String[] args) {
        /*Properties info = new Properties();
        info.setProperty("刘强东", "章泽天");
        info.setProperty("文章", "马伊利");
        info.setProperty("贾乃亮", "李小璐");
        info.setProperty("罗志祥", "周扬青");

        // void store(Writer out, String comments)
        try(Writer writer = new FileWriter("a.txt")) {
            info.store(writer, "...");
        } catch (IOException e) {
            e.printStackTrace();
        }*/

        // void load(Reader read)
        /*Properties info = new Properties();
        try (Reader reader = new FileReader("a.txt")) {
            info.load(reader);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(info);*/

        // void storeToXML(OutputStream os, String comment)
        /*Properties info = new Properties();
        info.setProperty("刘强东", "章泽天");
        info.setProperty("文章", "马伊利");
        info.setProperty("贾乃亮", "李小璐");
        info.setProperty("罗志祥", "周扬青");
        try(OutputStream out = new FileOutputStream("b.xml")) {
            info.storeToXML(out, "...");
        } catch (IOException e) {
            e.printStackTrace();
        }*/

        // void loadFromXML(InputStream in)
        Properties info = new Properties();
        try(InputStream in = new FileInputStream("b.xml")) {
            info.loadFromXML(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(info);
    }
}

····················································································································································································································

PPT上的三道题:

  1. “aababcabcdabcde”,获取字符串中每一个字母出现的次数要求结果:a(5)b(4)c(3)d(2)e(1)
    大致思路同LeetCode之根据字符出现频率排序
public class Homework01 {

    public static void main(String[] args) {
        String s = "aababcabcdabcde";
        String ret = charCount(s);
        System.out.println(ret);
    }

    public static String charCount(String s) {
        Map<Character, Integer> map = new TreeMap<>();
        for (int i = 0; i < s.length(); i++) {
            //if (map.containsKey(c)) map.put(c, map.get(c) + 1);
            //else map.put(c, 1);
            map.put(s.charAt(i), map.getOrDefault(s.charAt(i), 0) + 1);
        }
        StringBuilder sb = new StringBuilder();
        Set<Map.Entry<Character, Integer>> entries = map.entrySet();
        for (Map.Entry<Character, Integer> e : entries) {
            Character key = e.getKey();
            Integer value = e.getValue();
            sb.append(key).append("(").append(value).append(")");
        }
        return sb.toString();
    }
}

  1. LeetCode之两数之和
    这道题用到了哈希表,工作中更常用的是HashMap,底层是哈希表,增删查时间复杂度都是O(1),而TreeMap底层是红黑树,增删查的时间复杂度是O(logN),也就是树的高度。
  2. 请设计一个猜数字小游戏,可以试玩5次。试玩结束之后,给出提示:游戏试玩结束,请付费。
package com.cskaoyan.exercise;

import java.io.*;
import java.util.Properties;
import java.util.Scanner;

/**
 * @author shihao
 * @create 2020-05-24 17:33
 */
public class ex01 {

    public static void main(String[] args) {
        Properties properties = new Properties();
        try (Reader r = new FileReader("count.txt")) {
            properties.load(r);
        } catch (Exception e) {
            e.printStackTrace();
        }
        String value = properties.getProperty("count");
        int num = Integer.valueOf(value);

        if (num > 5) {
            System.out.println("试玩结束,请付费");
            System.exit(0);
        } else {
            num++;
            properties.setProperty("count",String.valueOf(num));
            try(Writer w = new FileWriter("count.txt")){
                properties.store(w,null);
            } catch (IOException e) {
                e.printStackTrace();
            }
            GuessNumber.start();
        }

    }
}

class GuessNumber {
    public static void start() {
        int count = 0;
        while (true) {
            //一定要将(Math.random() * 100)强换为int
            //而不是只讲Math.random()强转为int
            int num = (int) (Math.random() * 100) + 1;
            Scanner in = new Scanner(System.in);
            System.out.println("请输入数据(1-100):");
            int guessNumber = in.nextInt();
            count++;
            if (guessNumber > num) {
                System.out.println("你猜的数字" + guessNumber + "大了");
            } else if (guessNumber < num) {
                System.out.println("你猜的数字" + guessNumber + "小了");
            } else {
                System.out.println("恭喜你," + count + "次猜中了");
                break;
            }
        }
    }
}

count.txt

#Sun May 24 18:12:45 CST 2020
count=1

····················································································································································································································
Map总结:

Map
      |-- HashMap
	|-- LinkedHashMap
      |-- Hashtable
                 	|-- Properties
      |-- TreeMap
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-玫瑰少年-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值