public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
-- Cloneable: copy
-- Serializable: 网络传输,存盘,持久化,根据版本号反序列化
}
数组: 在内存中是连续的存储的单元。查询快,插入慢。
链表:查询慢,插入删除快。
hash算法:散列算法,把任意长度值的key通过散列算法变换成固定长度的地址。eg.MD5
hashCode: ASCII码
HashMap: 数组+链表+红黑树
why 数组?
没有哈希冲突时,用数组存放。
why 链表?
用来解决哈希冲突的问题,有哈希冲突,多个元素放在数组的同一个位置, 形成链表。
1.7以前 用头插法,在并发情况下,线程1 执行了空间扩容,读到的是A->B, 线程中断,线程2又进行了扩容,链表重排序,变成了B->A, 那么线程1读到的B指向的就是A,会发生死循环。
为了避免这种情况,1.8 改成了尾插法。
why 红黑树?
当哈希冲突的数据很多时, 链表很长,但链表查询只能从第一个元素开始遍历查找,效率很低,因此当长度>8时,会转换成红黑树, 以提高查询效率。
HashMap -- Put 过程:
根据key计算hash,
数组是否为空 -- 如果为空,创建数组。
resize创建数组table并设置容量(16),加载因子为0.75, 因此容量为12的时候,会进行扩容,链表的长度大于8-1时,会变成红黑树, 当删除元素使链表长度变为6,红黑树会转变回链表结构。
数组不为空,根据hash值确定在数组中的位置i(table)。
判断table[i]是否为空,如果为空,说明该位置还没有元素存入,直接插入数据。
如果table[i]不为空,说明该位置已经有数据,发生了hash冲突,比较哈希值和key值是否相等。
如果相同, 修改原值返回原值。
如果不相同:判断长度>8-1(是否是红黑树)。
如果是红黑树, 遍历红黑树,看是否存在,没有就直接插入,有的话修改替换。
如果是链表,遍历链表,链表里没有该值,在链表尾部添加,链表长度>8-1,转为红黑树。
concurrentHashMap 和HashTable 的put 方法上 加了 synchronized,线程安全。
Cas:线程状态不改变
Lock:线程状态 运行--》阻塞
线程切换