数组/链表
数组(查询快 , 新增, 删除慢)
链表(查询慢, 新增,删除快 )
Collection (单列)(接口)(java.util)
常用方法
- c .add 新增一个元素, 返回值是固定 true
- c. clear 清空集合所有元素
- c.contains 判断集合中是否存在这个元素
- c.iterator 获取集合的迭代器
iterator . next 获取下一个元素
iterator . hasNext 判断是否有下一个元素
List (可重复)(接口)
-
有序集合/可以存储重复元素
-
并发修改异常
在用迭代器遍历集合时,不允许新增或者删除元素.新增或者修改后,再次调用next时, 就会抛出并发修改异常. 避免此异常的方法 : 用for循环遍历集合,不用迭代器遍历.
-
列表迭代器: ListIterator .继承自Iterator
列表迭代器可以从任一方向遍历集合. 提供上一个/下一个方法. 可以新增或者移除元素. 需要用列表迭代器提供的add方法.
-
增强for循环 , 其实底层是一个迭代器.
-
ArrayList (实现类)
底层数据结构是数组: 查询快 , 增删慢.
-
LinkedList (实现类)
底层数据结构是链表: 增删快,查询慢 特有功能: 针对头尾的操作,获取/新增/删除 等.
Set (不可重复)
-
底层是hashcode, 对集合的迭代顺序不做任何保证. 即每次遍历顺序都不一定一致.
hashcode特点 同一个对象的hashcode的值是一致的 默认情况下, 不同对象的hashcode不相同,但是通过方法重写, 是可以获得相同的
-
hashcode.
遍历的方式: 增强for 迭代器
-
HashSet(实现类)
底层数据结构是hash表 数组 + 链表实现 默认长度为16 通过hashcode 计算对象在hash表中的位置 : hashcode 对数组长度取模. 即除数组长度的余数.
-
HashSet保证元素唯一性的源码分析
先初始化hash表 根据插入对象的hash值计算对象的存储位置, 如果该位置没有元素就存储元素.如果该位置有元素. 将两个元素先进行hash值比较, 如果hash值不同,将元素添加到集合(也保存到hash表同样的位置) , 如果hash值相同. 再次调用对象的equals()方法进行比较该位置的所有元素, 如果不同,将元素添加到集合.
-
LinkedHashSet(有序不重复)
底层数据结构是hash表和链表 链表决定了迭代器中元素插入的顺序. hash表决定了元素不重复.
-
TreeSet(实现类)(有序不可重复)
元素是有序的. 默认是是根据元素的自然排序进行排序.也可以通过构造方法设置比较器排序. 自然排序 : 并不是按照元素添加顺序进行排序, 比如数字是根据从小到大的顺序进行排序的. 被自然排序的对象必须实现自然排序接口 Comparable,不然会抛出异常. 重写Cpmparable接口中的cpmparaTo()方法, 本方法如果return 0 ; 则认为返回的重复元素.如果返回正数则是认为在后面, 如果是负数则是认为在前面. 根据指定的比较器进行排序 new TreeSet<T>( new Comparator<T> )
Map (双列)
-
HashMap(实现类)
put() 新增元素put 方法, 后面赋值会覆盖之前的赋值. remove() 根据key移除元素,并返回vaule, 没有这个key时返回null keySet() 获取map中所有key的集合,用于map遍历
-
HashMap底层的数据结构是什么样的?
底层最核心的数据结构是数组。 map是长度可变的,但是数组是有固定长度的,所以map也是动态扩容.
-
hash算法的优化
1. 先取到key的hash值32位, 然后将二进制计算后的结果,向右移动16位,左数前16位用0补全。 2. 然后将hashcode和右移16位之后的hashcode进行亦或运算。高低16位算法。 3. 亦或运算后的结果再转换成一个32位的int值 则是这个key的hash值。 4. 寻址算法 : 上面得到的hash值进行‘与’运算 (n - 1)& hash &运算 相同则为1 , 不同则是0 核心:前16位是固定的,无需参与&运算,只有后16位实际进行了计算。 5. 计算后得到数组长度的一位位置。
-
为什么要如此优化数组寻址的过程?有什么优势?
因为取模运算性能较差,为了优化这个寻址算法,采用如上算法,得到的效果一样。
-
算法优化总结 :
hash算法的优化 : 对每个hash值,在低16位之中,让高低16位进行亦或, 保留了高低16位的特征,尽量避免了hash值后续出现冲突, 防止大家进入相同位置。 寻址算法的优化: 用与&运算替代了 取模运算,提升了性能。
-
HashMap是如何解决hash冲突?
如果经过取址算法计算后的值还是一致的。 此时底层会在这个数组的位置,挂一个链表,将多个key-value同时放在数组的一个位置里。 get时, 会找到这个链表,遍历这个链表,取出value。 如果链表过长,会把链表转化成红黑树。
-
HsahMap是如何进行扩容的
2倍扩容。默认是16位。 -> 32位数组。 扩容的时候 ,会重新进行寻址运算。之前的链表有可能会分开。
-
map集合的遍历
方式1 : 获取keySet , 遍历set , 获取到每个key , 通过可以获取value 方式2 : 获取所有键值对对象的集合 entrySet() ,获取Map.Entry<key,value>获取到键值.
Collections集合 工具类
常用方法
sort 指定list 按照升序排序
reverse 指定list 反转元素顺序
shuffle 重新随机排列元素顺序 (模拟洗牌)
哪些容器的线程安全的?
Vector
HashTable
HashTable 是线程安全的 , 这是他和HashMap的最大不同点 , 他的线程安全 , 在于在读写操作的时候都是synchronized .