Java基础(六) ---- 集合

Connection

List有下标 有序且可重复 存进顺序与取出顺序一致

ArrayList 一维数组
LinkedList 双向链表 
Vector 一维数组 线程安全
Stack 栈 线程安全

Set无下标 无序且不可重复 存入顺序与取出顺序不一致(无序!=随机)

HashSet 一维数组 根据Unicode码计算Hash值以此为顺序存入数组 底层由HashMap实现 LinkedHashSet 双向链表 底层由LinkedHashMap实现
TreeSet 二叉树 底层由TreeMap实现

Map

HashMap 无序 key是唯一的
JDK1.7:一维数组+单向链表,头插法
JDK1.8:一维数组+单向链表+红黑树,尾插法,计算hash值高16位^低16位
一维数组+单向链表 --> 一维数组 + 红黑树:数组长度大于64,并链表长度大于8
一维数组 + 红黑树 --> 一维数组+单向链表:红黑树节点小于6
为了提高查询效率加入红黑树

LinkedHashMap 双向链表

HashTable 线程安全(方法加锁,效率低,已弃用)

ConcurrentHashMap 线程安全(局部加锁)

TreeMap 针对key排序、红黑树,泛型需要实现comparable接口,或者comparator

Properties 配置文件

迭代器

Itr -- implements Iterator

cursor(游标), lastRet(当前下标), expectedModeCount(内部操作数)

ListItr -- implements ListIterator modCount外部操作数


添加元素、删除元素会++(即数组长度变化),个数发生改变

ArrayList

extends AbstractList implements LIst

elementData(数组容器), size(元素个数/指针)

默认容量:10
最大容量:Integer.MAX_VALUE-8(减八是为了存放数组头部信息)
扩容机制:原长度的1.5倍 初始化

无参构造:将空数组赋给数组容器,并调用有参构造,初始值10
有参构造:指定大小创建数组(若数组长度大,则使用有参构造指定长度创建,减少扩容次数与几率)

判断指定大小是否大于零
大于则创建容量为指定大小的数组
等于则将空数组(不同于无参构造所赋的空数组)赋给数组容器
小于则抛出异常

LinkedList

ArrayList和LinkedList的效率问题

ArrayList的数据结构:一维数组
LinkedList的数据结构:双向链表


添加数据不扩容的情况 -- ArrayList效率高(ArrayList直接添加元素)
添加数据扩容的情况 -- LinkedList效率高(ArrayList需要复制数组)
删除数据 -- LinkedList效率高(LinkedList直接解链)
修改数据 -- ArrayList效率高 查询数据 -- ArrayList效率高(一维数组高于链表查询效率)

在处理业务时,查询功能使用较多,ArrayList查询快,所以使用ArrayList的频率更高
存在队列模式与栈模式

Vector

JDK1.2出现的集合框架
Veckor(JDK1.0) 存在容量增量,默认容量:10

Array List与Vector的区别
ArrayList是JDK1.2才有的类,线程不安全,扩容机制是原长度的1.5倍
Vector是JDK1.0就有的类,线程安全(方法加锁),扩容机制需要判断容量增量,若容量增量为0,扩容机制就是原长度的2倍,容量增量大于0,扩容机制就是原长度+容量增量

TreeSet\TreeMap

TreeSet底层是将元素存入TreeMap中key的位置,value位置使用占位符占位
TreeMap中先判断是否有外置比较器再判断内置比较器(说明外置比较器优先级高于内置比较器) TreeMap内部类Entry(二叉树)

key value 父节点地址 左节点地址 父节点地址 红黑树

//Student实现了Comparable接口
TreeMap<Student, Integer> map = new TreeMap<Student, Integer>();
map.put(new Student("aaa",90),1);
map.put(new Student("bbb",60),2);
map.put(new Student("ccc",70),3);
map.forEach((student, integer) -> System.out.println(student+" - " + integer));

//Teacher未实现Comparable接口,唯有向TreeMap构造方法中添加外置比较器实现Teacher的比较
Comparator<Teacher> cmp = (Comparator<Teacher>) Comparator.comparingInt((Teacher o) -> o.getSalary());
TreeMap<Teacher, Integer> map = new TreeMap<>(cmp);
map.put(new Teacher("aaa", 2000),1);
map.put(new Teacher("bbb", 3000),2);
map.put(new Teacher("ccc", 2500),3);
map.forEach((teacher, integer) -> System.out.println(teacher + " - " + integer));

HashMap

(JDK1.7:一维数组+单向链表,头插法 JDK1.8:一维数组+单向链表+红黑树,尾插法)

默认长度为16,长度必须是2的幂
最大容量1<<30(十亿多)
默认负载因子0.75

添加put过程

获取key的hash值 -- hashCode()
通过hash值计算在数组中的下标
判断下标上是否有元素存在

没有 -- 创建entry对象,存入数组中
有 -- 判断多个key是否相同 -- (hash)&&(== || equals)

相同 -- 替换原value值
不同 -- 添加元素(JDK1.7头插法 , JDK1.8尾插法)

HashMap内部类Entry(单向链表)

key value hash next

Hash回环解决

如果出现了Hash回环,不应该怪HashMap,因为HashMap明确表示该类不是一个线程安全的类,多线程下应使用ConcurrentHashMap
使用线程安全的ConcurrentHashMap
多线程下使用HashMap可能出现的情况
一个线程不断添加元素,导致HashMap扩容
一个线程不断遍历元素(第一个线程在扩容期间发生了引用地址回环),当前线程遍历时就会出现脏数据

默认的负载因子为什么是0.75?

取得了时间与空间的平衡
负载因子过大,利用了空间,浪费了时间
负载因子过小,利用了时间,浪费了空间

减少Hash碰撞的方法?

重写equals和hashCode方法,equals底层为== 不重写就无法判断是否相同

为什么长度会是2的幂?(重要)

获取元素在数组的下标是 元素的hash值&数组长度-1
如果数组的长度不是2的幂,-1就会导致二进制中的某几位都是0,和元素的hash值做&运算,二进制上的某几位就永远是0,最终导致下标分布不均匀,浪费空间
为了优化哈希函数计算和解决哈希冲突的效率,以及提高HashMap在散列过程中的性能

  1. 散列桶的计算更高效:假设HashMap的容量是capacity = 2^n,那么capacity - 1的二进制表示形式将是n位全为1的数。例如,capacity = 16 (2^4),那么capacity - 1 = 15的二进制表示是1111。这种情况下,当计算元素在哪个桶时,可以使用元素的哈希码与capacity - 1进行按位与(hash & (capacity - 1)),而不需要执行昂贵的取模运算。因为在位运算中,与1进行与操作保持原值,与0进行与操作结果为0,这样可以快速计算得到桶的索引

  2. 减少哈希冲突:当容量为2的幂时,哈希函数的取值范围与容量相对应,这样可以减少哈希冲突的概率。因为在容量为2的幂的情况下,哈希码的高位与低位信息都被保留,有助于均匀分布元素到不同的桶中,从而减少了哈希冲突的可能性

  3. 支持动态扩容:HashMap在元素数量超过容量的75%(负载因子)时,会自动进行扩容。而在容量为2的幂的情况下,扩容时只需简单地将哈希码的高位进行拼接,从而快速地将元素重新分布到新的桶中

HashMap什么时候扩容?

如果映射关系个数大于等于阈值 并且 当前下标上的元素不为null,就扩容

JDK1.7HashMap与JDK1.8HashMap的区别?

JDK1.7HashMap
数据结构:一维数组+单向链表
计算hash值:位运算
单项链表插值法:头插法

JDK1.8HashMap
数据结构:
一维数组+单向链表--链表长度>8&&数组长度>64 -->一维数组+红黑树(目的:提高查询效率)
一维数组+红黑树--红黑树节点<6 --> 一维数组+单向链表
计算hash值:高16位^低16位(计算更加散列的hash值)
单项链表插值法:尾插法

JDK1.8HashMap为什么链表长度>8会转换位红黑树?

泊松分布,让储存使用合理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值