一、Array List的底层原理
Array List长度可变,而数组长度不可变。
Array List底层是由动态数组实现的,第一次添加元素前,会创建一个初始容量为 10的数组。
后面每次再添加元素前,都会检测数组中已有元素数量+新增元素数量是否大于当前数组长度,如果是,创建一个容量为原数组容量的1.5倍的新数组,将原数组的元素拷贝到新数组中。
二、Linked List的底层原理
LinkedList底层用双向链表实现,具有头指针和尾指针,可以快速的对头节点和尾节点进行操作,链表相对于数组而言,添加和删除效率要高,但是查询效率较低。每一个数据(节点)都包含3个部分,一个是数据本身item,一个是指向下一个节点的next指针,还有就是指向上一个节点的prev指针,另外,双向链表还有一个 first 指针,指向头节点,和 last 指针,指向尾节点
三、 hashmap的底层原理
1、HashMap是基于哈希表实现的,而哈希表的底层是数组加上链表的形式。
HashMap 是 Java 中用于存储键值对的一种数据结构,它基于哈希表实现。理解 HashMap 的底层实现原理可以帮助你更好地使用它,并在需要时进行优化。
-
哈希表:HashMap 的底层实现是一个数组,称为哈希表。这个数组的每个元素称为桶(bucket)。每个桶可以存储一个链表或者红黑树。
-
扩容机制:
1)当哈希表的的元素达到了阈值,16*默认负载因子0.75,也就是12个元素的时候,数组长度扩容为两倍32,阈值变为24 2)还有一种是在没有红黑树的情况下,添加元素后数组中某个链表的长度超过了8,数组会扩容为两倍(比如创建HashMap集合后刚开始添加元素全都在一个链表中,当链表长度是9的时候数组扩容成32,链表长度是10的时候数组扩容成64,此时再添加元素,满足了数组长度为64链表长度到达8的两个条件,链表转换成红黑树)map.put(k,v)实现原理
-
键值对存储:HashMap 存储键值对,每个键值对被包装成一个 Entry 对象。Entry 包含键、值和指向下一个 Entry 的指针(如果存在冲突的话,会形成链表)。
-
-
哈希函数:在向 HashMap 中插入键值对时,会根据键的哈希值计算出在数组中的索引位置。Java 中的哈希函数会对键的哈希值进行再次处理,以保证散列均匀分布。
-
处理哈希冲突:当两个不同的键通过哈希函数映射到了同一个桶时,就会发生哈希冲突。HashMap 使用链表法(在 JDK8 中引入了红黑树)来解决哈希冲
HashMap存储数据原理
1、用HashMap存储数据( put(key,value) )时,会先操作key调用.hashcode()方法得出hash值,然后再通过哈希算法转换成数组的一个下标,对应的就是在数组上的的存储位置。
2、如果该位置没有数据,则直接存储。如果该位置有数据,则会发生数据碰撞。
3、数据碰撞的时候遍历该位置上链表中的所有数据,并且通过equals()方法来比对每个数据的key。如果key相同的话,会将链表上该位置的数据进行覆盖。如果key不相同的话,在JDK1.8之前是实行的头插法,数据存储在链表头部,1.8之后实行的是尾插法数据存储在链表尾部。
4、JDK1.8之后,当链表上的节点个数(数据个数)大于等于8时并且数组长度不小于64的时候,链表数据结构自动进行树化转化成红黑树,当链表上的数据小于8个时,又会自动退化成链表
5、如果数组的长度小于64的话链表数据个数达到了8的话也不会转化成红黑树,而是先进行扩容,直到数组长度达到64
1、首先将k,v封装到Node对象当中(节点)。
2、然后它的底层会调用K的hashCode()方法得出hash值。
3、通过哈希表函数/哈希算法,将hash值转换成数组的下标,下标位置上如果没有任何元素,就把Node添加到这个位置上。如果说下标对应的位置上有链表。此时,就会拿着k和链表上每个节点的k进行equal。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals返回了true,那么这个节点的value将会被覆盖。
map.get(k)实现原理 1、先调用k的hashCode()方法得出哈希值,并通过哈希算法转换成数组的下标。
2、通过上一步哈希算法转换成数组的下标之后,在通过数组下标快速定位到某个位置上。重点理解如果这个位置上什么都没有,则返回null。如果这个位置上有单向链表,那么它就会拿着参数K和单向链表上的每一个节点的K进行equals,如果所有equals方法都返回false,则get方法返回null。如果其中一个节点的K和参数K进行equals返回true,那么此时该节点的value就是我们要找的value了,get方法最终返回这个要找的value。