2021-07-03笔记

双例集合

Map接口

定义了双例集合的存储特征,它不是Collection接口的子接口。双例集合的存储特征是以【key】与【value】结构为单位进行存储。体

现的是数学中的函数 y=f(x)的概念

Map 与collecton的区别
  • Collection 中的容器,元素是孤立存在的,向集合中存储元素采用一个个元素的方式存储
  • Map 中的容器,元素是成对存在的。每个元素由【键】与【值】两部分组成,通过键查找对对应的值
  • Collection 中的容器称为单列集合,Map中的容器称为双列集合
  • Map 中的集合不包含重复的键,值可以重复;每个键只能对应一个值
  • Map 中常用的容器为HashMap、TreeMap等
Map接口的常用方法
方法说明
V put(K key,V value)把key与value添加Map集合中
void putAll(Map m)从指定Map中将所有映射关系复制到此Map中
V remove(Object key)删除key对应的value
V get(Object key)根据指定的key,获取对应的value
boolean containsKey(Object key)判断容器中是否包含指定的key
boolean containsValue(Object value)判断容器中是否包含指定的value
Set keySet()获取Map集合中所有的hey,存储到Set集合中
Set<Map.Entry<K,V>> entrySet()返回一个Set基于Map.Entry类型包含Map中所有映射
void clear()删除Map中所有的映射

key相同,替换、覆盖

一个【key-value对】称为一个【映射】

HashMap容器类
  • HashMap是Map 接口的接口实现类,它采用哈希算法实现,是 Map接口最常用实现类
  • 由于底层采用了哈希表存储数据,所以要求键不能重复,如果发生重复,新的值会替换旧的值
  • HashMap在查找、删除、修改方面都有非常高的效率
添加元素
//实例化HashMap容器
        Map<String,String> map = new HashMap<>();

        /*
        添加元素,若容器中没有与要添加映射相同的key,返回值为null;
        若有,则【新value】替换【旧value】,并返回【旧value】
         */
        map.put("a", "A");
        String v1 = map.put("a", "B");
        System.out.println(v1);
获取元素的三种方式
  • get()
  • keySet() get()
  • 通过entryset方法获取Map.Entry类型获取元素(内部接口.外部接口???),返回的键值对
/*
        通过key获取value
        难点:
        1、如果要获取很多个value,需要每次都使用get方法
        2、如果我们事先并不知道key,就无法获取对应value
         */
        String s1 = map.get("a");
        System.out.println(s1);
map.put("b","B");
        map.put("c","C");
        map.put("d","D");
        map.put("e","E");
        
        /*
        使用keySet与get方法
        获取HashMap容器中所有元素
        成对输出
         */
        Set<String> keys = map.keySet();
        for (String key:keys){
            String val = map.get(key);
            System.out.println(key+" --- "+val);
        }
 /*
        一个Map.Entry相当于一个键值对【K-V】
         */
        Set<Map.Entry<String,String>> entrySet = map.entrySet();

        for (Map.Entry<String,String> entry:entrySet){
            String key = entry.getKey();
            String val = entry.getValue();
            System.out.println(key+" ---- "+val);
        }
Map容器的并集操作
/*
        并集操作
        如果两容器中有相同的key,则原容器中的value将被覆盖
         */
        Map<String,String> map2 = new HashMap<>();
        map2.put("f","F");
        map2.put("c","cc");
        map2.putAll(map);

        Set<Map.Entry<String,String>> entrySet2 = map2.entrySet();

        for (Map.Entry<String,String> entry2:entrySet2){
            String key2 = entry2.getKey();
            String val2 = entry2.getValue();
            System.out.println(key2+" ------ "+val2);
        }
删除元素
System.out.println("------------通过key删除对应value-------------");
        String v = map.remove("e");
		System.out.println(v);//返回删除的value
        Set<String> keys1 = map.keySet();
        for (String key:keys1){
            String k1 = map.get(key);
            System.out.println(key+" --- "+k1);
        }
如何判断key或value是否存在
boolean flag1 = map.containsKey("d");
        System.out.println(flag1);
        boolean flag2 = map.containsValue("B");
        System.out.println(flag2);
HashMap底层存储特征
  • 数组:占用空间连续,寻址易,查询快,增删效率低

  • 链表:占用空间不连续,寻址难,查询慢,增删效率高

  • 数组+链表—哈希表

    JDK8,哈希表优化,红黑树

HashMap源码分析
  • static final float DEFAULT_LOAD_FACTOR = 0.75f

    容器空间使用75%时就扩容,不是达到100%才扩容

  • static final int TREEIFY_THRESHOLD = 8

    节点数大于8,才可能进行链表树型化(第二条件)

  • static final int MIN_TREEIFY_CAPACITY = 64

    数组长度大于64,才会可能进行链表树型化(第一条件)

  • 数组初始化

    JDK8的HashMap中数组采用延迟初始化。resize方法既实现数组初始化,也实现数组扩容处理

计算哈希值(面试常问)/P231

元素放入节点,节点放入数组或数组中某一链表或红黑树,计算哈希值决定节点在数组的位置???

(1)获得key对象的hashcode

调用key对象的hashcode()方法,获得key 的hashcode值

(2)根据hashcode计算出hash值(要求在**[0,数组长度-1]**区间)

hashcode是一个整数,需要将它转化成**[O,数组长度-1]范围内的整数。且要求转化后的hash值尽量均匀地分布在区间,减少“hash冲突”**

  • —种极端简单和低下的算法

    • hash值= hashcode/hashcode;
    • 哈希值始终为1,所有元素所在节点都将放在数组中索引为1的位置
  • —种简单和常用的算法—相除取余算法

    • hash值=hashcode%数组长度
    • 这种算法可以让hash值均匀分布在区间。但由于使用了除法,效率低下。
    • 改进的算法:首先约定数组长度必须为2的整数幂,现在采用位运算即可实现取余的效果: hash值=hashcode&(数组长度-1)。

(3)具体计算过程(二进制)

  • h = key.hashcode()
  • h >>>16(取高16位)
  • 两者做异或运算^得到一个过程中的哈希值
  • 数组长度-1
  • 两者做与运算&得到一个最终的哈希值
  • 转为十进制

(4)容器容量0-16-32,阈值为其容量的0.75倍,达到即扩容至2倍

TreeMap容器类

TreeMap和HashMap同样实现了Map接口,所以,对于API的用法来说是没有区别的。HashMap效率高于TreeMap;TreeMap是可以对

【键】进行排序的一种容器,在需要对键排序时可选用TreeMap。TreeMap底层是基于红黑树实现的。

在使用TreeMap时需要给定排序规则:

  • 元素自身实现比较规则

    /*
            实例化TreeMap容器
            Users作为Key,String作为value
            Key实现比较规则
             */
            Map<Users,String> map = new TreeMap<>();
            Users u1 = new Users("cyf",18);
            Users u2 = new Users("damin",22);
            Users u3 = new Users("admin",22);
            map.put(u1,"cyf");
            map.put(u2,"damin");
            map.put(u3,"admin");
    
            Set<Users> keys = map.keySet();
            for (Users user:keys){
                Users u = user;
                System.out.println(u);
            }
    
    package com.cyf;
    
    public class Users implements Comparable<Users> {
        private String username;
        private int userage;
    
        public Users() {
        }
    
        public Users(String username, int userage) {
            this.username = username;
            this.userage = userage;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public int getUserage() {
            return userage;
        }
    
        public void setUserage(int userage) {
            this.userage = userage;
        }
    
        @Override
        public String toString() {
            return "Users{" + "username'" + username + '\'' + ",userage=" + userage + '}';
        }
    
        //定义比较规则:正数,大;0,相等;负数,小
        @Override
        public int compareTo(Users o) {
            if (this.userage > o.getUserage()){
                return 1;
            }//年龄相等即无所谓先后
    
            if (this.userage == o.getUserage()){
                return this.username.compareTo(o.getUsername());
            }
            return -1;
        }
    }
    
  • 通过比较器实现比较规则

    System.out.println("-----------------------------");
            Map<Student,String> treeMap = new TreeMap<>(new StudentComparator());
            Student s1 = new Student("cyf",18);
            Student s2 = new Student("admin",22);
            Student s3 = new Student("sxt",22);
    
            treeMap.put(s1,"cyf");
            treeMap.put(s2,"admin");
            treeMap.put(s3,"sxt");
    
            Set<Student> keys1 = treeMap.keySet();
            for (Student s:keys1){
                System.out.println(s+"----"+treeMap.get(s));
            }
    
    public class StudentComparator implements Comparator<Student> {
    
        //比较器  定义比较规则
        @Override
        public int compare(Student o1, Student o2) {
            if (o1.getAge() > o2.getAge()){
                return 1;
            }
            if (o1.getAge() == o2.getAge()){
                return o1.getName().compareTo(o2.getName());
            }
            return -1;
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值