java基础 -- java集合(二)

Map

  • 用于保存Key-value形式的数据
  • Map的Key用Set存放,不允许重复
  • key、value可以是任意形式的数据,且必须存在一一对应的关系,一对<Key,value>称为一个Entry

HashMap

  • HashMap是使用频率最高的实现类

Hash

数组优劣势:快速查找;需要开辟一整块内存空间,插入删除元素及“”扩容“”’起来比较困难
在这里插入图片描述
链表优劣势:不用开辟整块内存空间,插入删除元素较方便;查找元素需要按头、尾指针逐个遍历各个元素,比较慢

在这里插入图片描述
HashMap:
综合了数组和链表的优点,采用数组+链表的形式实现,java8以后采用数组+链表+红黑树的形式实现,发生hash碰撞时,数组同一个位置上的元素以链表的形式进行存储,当链表的长度达到8时,该位置的链表升级为红黑树
**红黑树:**自平衡的二叉查找树,引入红黑树就是为了解决链化严重的问题,提高查找效率
在这里插入图片描述

Hash特点:
将任意长度的输入,通过某种映射规则变成固定长度的输出
映射规则就是对应的Hash算法,映射后的二进制串就是哈希值

  • 执行高效,长文本也能很快计算出哈希值
  • 不能通过哈希值反推出原始数据
  • 输入数据微小变化都会得到不同的哈希值,相同数据具有相同的哈希值
  • hash的原理是将输入空间的值映射到hash空间内,而hash空间远小于输入的空间,所以,哈希碰撞在所难免-----这就是为什么添加过程中hash key的哈希值相同,需要使用equals()方法,equals方法不同的话,数据依旧可以添加成功

HashMap

使用方法:

        HashMap<Integer, String> map = new HashMap<>();
//        添加元素
        map.put(1, "a");
        map.put(2, "b");
        map.put(3, "c");
        map.put(4, "d");
        map.put(5, "e");
        map.put(6, "f");
        map.put(7, "g");

//        输出列表形式
        System.out.println("toString形式:");
        System.out.println(map);

//      key以Set的形式进行存储,不可重复
//      当前key值类型为整型
        Set<Integer> keys = map.keySet();
        System.out.println("KEY:");
        System.out.println(keys);//使用迭代器循环

        System.out.println("迭代器遍历形式:");
//      value以Collection 的形式存储,可以重复
//      当前value类型为String
        Collection<String> values = map.values();
        Iterator<String> iterator = values.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

  • 所有的key构成的集合是Set:无序的不可重复的。所以,key所在的类要重写:equals()和hashCode()

  • 所有的value构成的集合是Collection:无序的可以重复的。所以,value所在的类要重写:equals()

  • 一个key-value构成一个entry,所有的entry构成的集合是Set:无序的、不可重复的

  • HashMap 判断两个 key 相等的标准是:两个 key 通过 equals() 方法返回 true,hashCode 值也相等。

  • HashMap 判断两个 value相等的标准是:两个 value 通过 equals() 方法返回 true

重要常量:

     //默认数组长度为16
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
    // 最大容量:2^30
    static final int MAXIMUM_CAPACITY = 1 << 30;
   //默认设定的负载因子
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
   //树化阈值,链表长度超过8,链表转化为红黑树
    static final int TREEIFY_THRESHOLD = 8;
	//树降级成为链表的阈值
    static final int UNTREEIFY_THRESHOLD = 6;
   // 第二个树化阈值----数组元素个数至少要达到64,且链表长度达到8,才能转化成红黑树
    static final int MIN_TREEIFY_CAPACITY = 64;

   //其余重要概念:
    table:存储元素的数组,总是2的n次幂
	entrySet:存储具体元素的集
	size:HashMap中存储的键值对的数量
	modCount:HashMap扩容和结构改变的次数。
	threshold:扩容的临界值,=容量*填充因子
	loadFactor:填充因子

HashMap的扩容原理:
前面说过,hash空间远小于输入空间,同时由于数组的长度是固定的,因此,当HashMap中的元素越来越多的时候,hash冲突的几率也就越来越高,使得链化逐渐严重,而链表查询需要逐个比较各个链表元素,极大地降低了查询效率。
所以需要对HashMap的数组进行扩容,提升查询效率。在HashMap数组扩容之后,原数组中的数据必须重新计算其在新数组中的位置,并放进去,这就是resize()方法

何时扩容及扩容细节?
数组长度为length(默认值为16),负载因子为loadFactor(默认值为0.75),当HashMap中的元素个数超过length* loadFactor时(16* 0.75=12),数组进行扩容。扩容后,数组的大小扩展为原来长度的2倍,即 2*16=32,然后重新计算每个元素在数组中的位置,这是一个非常消耗性能的操作,所以如果预知HashMap中元素的个数,那么预设元素的个数能够有效的提高HashMap的性能
当HashMap中的其中一个链的对象个数如果达到了8个此时如果capacity没有达到64,那么HashMap会先扩容解决,如果已经达到了64,那么这个链会变成树结点类型由Node变成TreeNode类型。当然,如果当映射关系被移除后,下次resize方法时判断树的结点个数低于6个,也会把树再转为链表。

JDK1.8相较于之前的变化:

  1. HashMap map = new HashMap();//默认情况下,先不创建长度为16的数组
  2. 首次调用map.put()时,再创建长度为16的数组
  3. 数组为Node类型,在jdk7中称为Entry类型
  4. 形成链表结构时,新添加的key-value对在链表的尾部(七上八下)
  5. 当数组指定索引位置的链表长度>8时,且map中的数组的长度> 64时,此索引位置上的所有key-value对使用红黑树进行存储。

负载因子对HashMap的影响

负载因子的大小决定了HashMap的数据密度

  • 负载因子越大密度越大,发生碰撞的几率越高,数组中的链表越容易长,造成查询或插入时的比较次数增多,性能会下降。
  • 负载因子越小,就越容易触发扩容,数据密度也越小,意味着发生碰撞的几率越小,数组中的链表也就越短,查询和插入时比较的次数也越小,性能会更高。但是会浪费一定的内容空间。而且经常扩容也会影响性能,建议初始化预设大一点的空间。
  • 按照其他语言的参考及研究经验,会考虑将负载因子设置为0.7~0.75,此时平均检索长度接近于常数。

LinkedHashMap

是HashMap的子类,在HashMap存储结构的基础上,使用一对双向链表来记录添加元素的顺序
与LinkedHashSet相似,LinkedHashMap可以维护Map的迭代顺序-----与Key-value对的插入顺序一致
图片来自尚硅谷课件

TreeMap

  • TreeMap存储 Key-Value 对时,需要根据 key-value 对进行排序
    TreeMap 可以保证所有的 Key-Value 对处于有序状态
  • TreeSet底层使用红黑树结构存储数据

TreeMap 的Key 的排序:

  1. 自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出ClasssCastException
  2. 定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现Comparable 接口TreeMap判断两个key相等的标准:两个key通过compareTo()方法或者compare()方法返回0。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值