Java集合框架
java集合框架主要分两种容器,集合Collection和图Map
Collection
Collection是List、Set、Queue的父接口,提供了基本的集合操作crud等。
List
List是一种有序集合,可以包含重复的元素。java中的List的实现类主要有ArrayList、LinkedList、Stack等。
ArrayList
基于动态数组实现的列表,存储结构上是连续的,适合用下标访问。
数组的容量是固定的,ArrayList容量可以同构造函数指定,一旦超出使用add会自己扩容,无参构造函数实例化对象容量为0,进行一次add操作后容量会变成默认的10(初始化指定容量比10小也会),长度到达10以后会再进行扩容扩容的量是newCapacity = oldCapacity + (oldCapacity >> 1)即1.5倍扩容。这里的容量和ArrayList的size不是同一个东西。
LinkedList
基于链表实现,存储结构上非连续,适合插入或者删除。
链表逻辑顺序是通过引用链接次序实现的,再插入或者删除的时候只需要修改删除或增加一个数据元素再修改对应的Node就可以,不需要像ArrayList考虑是否需要扩容和进行arraycopy,但是由于是链表的结点物理上是不连续的查询(如:获取某个index的元素都需要去遍历)。这就是为什么说ArrayList更适合查询,不适合做插入和删除,LinkedList更适合做插入和删除而不适合做查询。但不代表ArrayList做插入一定会比LinkedList慢,如上图ArrayList使用add()在尾部插入时,在容量不需要扩容的情况下只是单纯的数组赋值这样的操作并不会比LinkedList的add()慢。
Set
Set是无序的集合,Set不保存重复元素。主要的实现类有HashSet
HashSet
底层是通过HashMap去实现的
Map
Map接口是一组键值对的容器,可以根据键快速查找对应的值,主要的实现类有HashMap、LinkedHashMap、ConcurrentHashMap、TreeMap等
HashMap
键值对,底层结构是数组加链表加红黑树。HashMap将键和值存储在哈希表中,并根据键的HashCode值来快速定位和访问值,因此可以实现高效的查找和操作。
简单的源码解读
底层是一个Node<K,V>的数组
Node<K,V>类
put方法调用的是putVal方法
putVal()方法解读
resize()扩容会如下几个操作:
- 计算扩容后容量大小、以及扩容阈值(下一次扩容的阈值)
- 根据计算出来的容量实例化一个新的Node<K,V>数组,把旧的Node<K,V>数组数据转移到新的数组
- 为什么要使用红黑树?
因为当链表长度过长时通过key依次查找的效率过低,所以会将链表转换为红黑树
- 为什么用红黑树而不用AVL树
1、AVL是绝对平衡的,插入数据需要经过多次旋转来达到绝对平衡,而红黑树不是绝对平衡树,最多需要三次旋转。旋转会耗费更多时间,而HashMap需要高效的查找、插入、删除操作。
2、AVL树相对于红黑树可能需要更多的额外存储空间来维护平衡性。AVL树需要为每个节点存储平衡因子,用于记录左右子树的高度差。这个额外的存储开销会增加树结构的总体内存使用量。而红黑树只需要为每个节点存储一个颜色标志,用于区分红色和黑色节点,相对而言,内存开销较小。