文章目录
容器
1 List
- ArrayList:Object[]数组
- Vector:Object[]数组
- LinkedList:双向链表
1.1 ArrayList和Vector区别
- ArrayList是List的主要实现类,Object[]数组,线程不安全
- Vector是List的古老实现类,Object[]数组,线程安全
1.2 ArrayList和LinkedList区别
- 两者都是线程不安全
- ArrayList使用Object[]数组,LinkedList使用双向链表
- ArrayList的数组结构利于随机查找,LinkedList的链表结构利于增加和删除
- ArrayList的空间主要浪费在列表结尾预留的容量空间,LinkedList的空间主要浪费在存储前驱和后继
1.3 ArrayList
继承于AbstractList,实现了List、RandomAccess、Cloneable、Serializable接口
- RandomAccess:用于标记该集合支持快速随机访问
- Cloneable:意味着该集合能被克隆
- Serializable:意味着该集合支持序列化
扩容机制
- 初始化时是空数组,当插入第一个元素时数组容量变成10,minCapacity=Math.max(10, minCapacity)
- 当插入新元素时,直到所需要的最小容量minCapacity大于数组容量时,会将数组扩容为原先的1.5倍
- 如果newCapacity还是小于minCapacity,则将新容量设置为minCapacity
- 如果newCapacity大于最大容量限制Integer.MAX_VALUE,则将新容量设置为Integer.MAX_VALUE-8
1.4 Arrays.copyOf
// 以正确顺序复制一份当前列表,size表示新列表的长度
Arrays.copyOf(oldArr, size);
1.5 Arrays.asList
将数组转换为集合,但是底层仍然是数组,无法使用集合的相关方法
当传入的是基本数据类型数组,则集合种只有一个元素,这个数组本身
// 正确转换方式
List list = new ArrayList<>(Arrays.asList("a", "b", "c"));
List myList = Arrays.stream(myArray).collect(Collectors.toList());
List myList = Arrays.stream(myArray2).boxed().collect(Collectors.toList());
2 Set
- HashSet:底层是HashMap,线程不安全,可以存储null值
- LinkedHashSet:HashSet的子类,底层是LinkedHashMap,能够按照添加顺序遍历
- TreeSet:底层使用红黑树,能够排序
2.1 如何检查重复
- 首先计算对象的hashCode,如果没有相同的元素,则插入
- 如果存在相同的元素,则用equals方法对比两个元素
3 Map
- HashMap:JDK1.7之前采用数组+链表的拉链法,JDK1.8以后当链表长度大于8时,将链表转换为红黑树(如果当前数组的长度小于64,则会先扩容数组,而不是转换红黑树)
- LinkedHashMap:继承自HashMap,能够按照添加顺序遍历
- HashTable:数组+链表,线程安全
- TreeMap:底层使用红黑树,能够排序
3.1 HashMap和Hashtable区别
- HashMap线程不安全,HashTable线程安全
- HashTable基本已经被淘汰
- HashMap可以存储null值,HashTable不允许存储null值
- HashMap默认容量16,扩容机制采用2的幂次方,HashTable默认容量11,扩容机制采用2n+1
3.2 HashMap
3.2.1 JDK1.7以前
数据结构:采用数组+链表形式,通过拉链法防止哈希冲突
计算哈希方法:经过扰动函数处理得到hash值,通过**(n-1)&hash**判断当前元素存放位置
// 扰动函数
static int hash(int h) {
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
3.2.2 JDK1.8以后
数据结构:采用数组+链表+红黑树形式,当链表长度大于8时,将链表转换为红黑树(如果当前数组的长度小于64,则会先扩容数组,而不是转换红黑树)
计算哈希方法:经过扰动函数处理得到hash值,通过**(n-1)&hash**判断当前元素存放位置
// 扰动函数
static final int hash(Object key) {
int h;
// key.hashCode():返回散列值也就是hashcode
// ^ :按位异或
// >>>:无符号右移,忽略符号位,空位都以0补齐
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
4 Collections
void sort(List list) //按自然排序的升序排序
void sort(List list, Comparator c) //定制排序,由Comparator控制排序逻辑
void reverse(List list) //反转
void shuffle(List list) //随机排序
void swap(List list, int i , int j) //交换两个索引位置的元素
void rotate(List list, int distance) //旋转。当distance为正数时,将list后distance个元素整体移到前面。当distance为负数时,将 list的前distance个元素整体移到后面
int binarySearch(List list, Object key) //对List进行二分查找,返回索引,注意List必须是有序的
int max(Collection coll) //根据元素的自然顺序,返回最大的元素
int max(Collection coll, Comparator c) //根据定制排序,返回最大元素
void fill(List list, Object obj) //用指定的元素代替指定list中的所有元素。
int frequency(Collection c, Object o) //统计元素出现次数
int indexOfSubList(List list, List target) //统计target在list中第一次出现的索引,找不到则返回-1
boolean replaceAll(List list, Object oldVal, Object newVal) //用新元素替换旧元素
5 使用Iterator在遍历中删除元素
Iterator<String> iterator = list.listIterator();
while (iterator.hasNext()){
iterator.remove();
}