java集合专题Map接口及HashMap/Hashtable/Properties使用方法底层结构及源码分析

举报
bug郭 发表于 2022/10/06 22:52:59 2022/10/06
【摘要】 大家好,我是bug郭,一名双非科班的在校大学生。对C/JAVA、数据结构、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流作者简介:CSDN java领域新星创作者blog.csdn.net/bug…掘金LV3用户 juejin.cn/user/bug…阿里云社区专家博主,星级博主,developer.a...

大家好,我是bug郭,一名双非科班的在校大学生。对C/JAVA、数据结构、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流

作者简介:

Map接口

Map接口我们主要学习其下的HashMap/Hashtable/TreeMap/Properties4个主要实现类

在这里插入图片描述
Map不同于Colletion接口下的List和Set! Map是双列集合存放的是键值对的形式!
Key-Value的形式进行存储

  • 无序,无法保证插入顺序和取出顺序一致
  • key可以为null且唯一,value可以为null
  • Map中的key-value是任意引用数据类型,会封装在HashMap&Node对象中!

Map接口常用方法

在这里插入图片描述

public class Map_ {
    public static void main(String[] args) {
        Map<String,Integer> map = new HashMap<>();
        //添加元素!
        map.put("李白",19);
        //通过key获取value!
        System.out.println("李白:"+map.get("李白"));
        //删除元素!
        map.remove("李白");
        System.out.println("size:"+map.size());
        //替换,如果需要替换的key不存在,不会添加该元素(和put的区别)
        map.replace("李白",100);
        System.out.println(map);
        Map<String,Integer> map1 = new HashMap<>();
        map.put("李白",190);
        map1.put("曹操",18);
        map1.put("关羽",31);
        map1.put("张飞",12);
        //添加map1到map中!
        map.putAll(map1);
        System.out.println(map);
    }
}

在这里插入图片描述

Map遍历方式

使用下面的4种方法从而实现map遍历

  • containsKey:查找key是否存在
  • KeySet:获取map所有key值
  • entrySet:获取所有的key-value
  • values:获取所有的value
    在这里插入图片描述
    注意:这里map下的键值对是通过Node进行存储的!
    这里的keySet或者 Map.Entry只是保存的索引值,只是为了遍历方便!
public class MapFor {
    public static void main(String[] args) {
        Map<String,Integer> map = new HashMap<>();
        for (int i = 0; i < 5; i++) {
            map.put(i+"",i*i);
        }
        System.out.println("===1.keySet获取key后通过get获取value===");
        Set<String> keyset = map.keySet();
        System.out.println("1.1迭代器遍历");
        Iterator<String> iterator = keyset.iterator();
        while (iterator.hasNext()){
            String next = iterator.next();
            System.out.print(next+"->"+map.get(next)+" ");
        }
        System.out.println("\n===1.1增强for遍历===");
        for ( String x:keyset) {
            System.out.print(x+"->"+map.get(x)+" ");
        }
        //我们知道set没有get方法所以不能进行普通for遍历!
        System.out.println("\n===2.通过EntrySet获取到key-value===");
        //这里注意:因为entrySet的类型Map.Entry:map下的Entry存放了Node的key-value引用
        Set<Map.Entry<String, Integer>> entries = map.entrySet();
        System.out.println("===2.1迭代器iterator遍历===");
        Iterator<Map.Entry<String, Integer>> iterator1 = entries.iterator();
        while (iterator1.hasNext()){
            Map.Entry<String,Integer> next = iterator1.next();
            //Map.Entry类提供了 getKey 和 getValue 方法!
            System.out.print(next.getKey()+"->"+next.getValue()+" ");
        }
        System.out.println("\n===2.2增强for遍历===");
        for (Map.Entry<String,Integer> x : entries) {
            System.out.print(x.getKey()+"->"+x.getValue()+" ");
        }
        //这里依然是得到的set集合,而set没有get方法,不能普通for遍历
        System.out.println("\n===3.values方法获取所有的value值===");
        //注意这里values方法返回的是Collection接口实现类
        Collection<Integer> values = map.values();
        System.out.println("===3.1迭代器遍历===");
        Iterator<Integer> iterator2 = values.iterator();
        while (iterator2.hasNext()){
            Integer next = iterator2.next();
            System.out.print(next+" ");
        }
        System.out.println("\n===3.2增强for遍历===");
        for (Integer x :values) {
            System.out.print(x+" ");
        }

    }
}

在这里插入图片描述

练习题

使用HashMap添加3个员工对象
要求key:员工id 值: 员工对象
遍历结果显示工资> 18000的员工
员工类:姓名,工资,员工id

public class MapExercies {
    //员工类!
    static class Emp{
        private int id;
        private String name;
        private int sal;
        public Emp(int id, String name, int sal) {
            this.id = id;
            this.name = name;
            this.sal = sal;
        }

        @Override
        public String toString() {
            return "Emp{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", sal=" + sal +
                    '}';
        }
    }

    public static void main(String[] args) {
        Map<Integer,Emp> map = new HashMap<>();
        map.put(1,new Emp(1,"刘备",16000));
        map.put(4,new Emp(4,"曹操",19000));
        map.put(2,new Emp(2,"吕布",1000));
        //entrySet方法先获取到 key-value
        Set<Map.Entry<Integer,Emp>> entries = map.entrySet();
        System.out.println("=迭代器遍历=");
        Iterator<Map.Entry<Integer, Emp>> iterator = entries.iterator();
        while (iterator.hasNext()){
            Map.Entry<Integer,Emp> next = iterator.next();
            if(next.getValue().sal>18000){
                System.out.println(next.getKey()+"->"+next.getValue());
            }
        }
        Set<Integer> keyset = map.keySet();
        System.out.println("=keySet增强for遍历=");
        for (Integer key : keyset) {
            if(map.get(key).sal>18000){
                System.out.println(key+"->"+map.get(key));
            }
        }

    }
}

在这里插入图片描述

HashMap

  • HashMap是Map接口中使用频率最高的类
  • HashMap是以key-value的形式存储(HashMap$Node类型)
  • Key值不能重复,value可以重复如果key相同,key不变,value会覆盖,允许key和value为空
  • 和HashSet一样不能保证映射顺序,hash表的方式存储(jdk8底层是数组+链表+红黑树)
  • HashSet没有实现线程同步,线程不安全

底层结构源码分析

在这里插入图片描述

重点:

扩容机制:和HashSet相同
1.HashMap底层维护了Node类型的table,默认为空
2.创建对象初始化,只是将装载因子(loadfacter)赋值为0.75
3.判断2个key相同的方式:先hash处理(调用该key的hashCode方法获取h^h>>>16),然后进行索引映射(i=(len-1)%hash),如果索引位置为空直接添加,如果非空判断引用是否相同 | | equals是否相同如果满足其一就说明key相同进行value覆盖,否则链表尾插
3.当添加第一个对象时,第一次扩容为16(threshold阀值为16*0.75)
4.以后进行扩容,超过阀值就进行2倍扩容,然后更新阀值
5.在jdk8当一条链表的长度超过8就会进行树化判断,如果当前容量(数组的长度)大于等于64就会将该链红黑树树化如果未达到数组长度未到达64就会进行2倍扩容

这里的源码分析和HashSet一样就不在进行分析了,下次一定(等忘了再来!)

Hashtable

在这里插入图片描述

  • Hashtable类和HashMap底层相同不过是数组+链表不会树化
  • Hashtable线程安全,方法添加了synchronized关键字
  • Hashtable中key和value都不能为空!
  • 初始化容量即为11,然后loadfactor=0.75
  • 扩容方式,超过阀值就就进行扩容,2倍+1

底层结构源码分析

在这里插入图片描述

TreeMap

  • TreeMap底层是一颗红黑树
  • TreeMap可以传入比较器进行排序
  • TreeMap无序集合(插入和读取不一致)
  • TreeMap可以为null

在这里插入图片描述可以看到TreeMap继承了AbstractMap类
在这里插入图片描述
AbstractMap类继承了Map接口这样就减少了TreeMap类实现Map接口的复杂性,直接继承AbstactMap类即可! 这里还继承了NavigableMap接口
在这里插入图片描述
而NavigableMap实现了SorteMap接口!
SortMap接口有comparator方法,所以TreeMap类可以传入比较器进排序
在这里插入图片描述

public class TreeMap_ {
    //通过年龄进行排序
   static class Emp{
        private String name;

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

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

        private int age;
    }
    public static void main(String[] args) {
        TreeMap<Emp,String> treeMap = new TreeMap<>(new Comparator<Emp>() {
            @Override//年龄升序排列
            public int compare(Emp o1, Emp o2) {
                return o1.age-o2.age;
            }
        });
        treeMap.put(new Emp("刘备",123),"1");
        treeMap.put(new Emp("张飞",888),"1");
        treeMap.put(new Emp("李白",5),"1");
        System.out.println(treeMap);
    }

}

在这里插入图片描述

源码分析

在这里插入图片描述
有点复杂红黑树的插入,所以咱们后面再回来干他!

Properties

Properties类继承了Hashtable!
他主要特点就是为了读取.properties等资源配置配置文件用于IO操作的一个类!

  • key-value都为字符串
  • 虽然Hashtable的那些方法都能用,我们一般都是用该类下特有的方法

在这里插入图片描述

public class Properties_ {
    public static void main(String[] args) throws IOException {
        Properties properties = new Properties();
        //保存数据
        properties.setProperty("刘备","14");
        properties.setProperty("李白","24");
        properties.setProperty("张飞","13");
        //获取数据
        System.out.println("李白:"+properties.getProperty("李白"));
        //将数据保存到配置文件!
        OutputStream file = new FileOutputStream("db.properties",true);
        properties.store(file,"注解");
        System.out.println(properties);
        //读数据!
        Properties prop = new Properties();
        prop.load(new FileReader("db.properties"));
        System.out.println(prop);
    }
}

在这里插入图片描述

在这里插入图片描述

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。