Day8 集合
常用集合体系图(中间省略了一些结构)
较为完整的体系结构
- List:无序可重复
- Set:有序不可重复
- Map:键值对,键不可重复,值可以
常用范围 | 底层实现方式 | 线程是否安全 | 扩容 | 初始值 | |
---|---|---|---|---|---|
ArrayList | 查/改 | Object数组 | n | 1.5倍 | 10 |
LinkedList | 添加/删除 | 双向链表和双端队列 | n | 链表追加 | |
Vector | 要求线程安全 | Object数组 | y | 2 | 10 |
HashSet | 去重 | HashSet | n | 2 | 16 |
LinkedHashSet | LinkedHashMap | n | 2 | 16 | |
TreeSet | 有排序需求 | TreeMap | n | ||
HashMap | 有键值对需求 | 数组/链表/红黑树 | n | 2 | 16 |
HashTable | 线程安全 | 数组/链表 | y | 2倍 + 1 | 11 |
LinkedHashMap | 数组/链表 | n | 2 | 16 | |
TreeMap | 红黑树 | n | |||
Properties | 读取配置文件 | 继承自Hashtable,实现了Map |
Iterator接口(迭代器)
- boolean hasNext():如果仍有元素可以迭代,则返回 true。
- E next():返回迭代的下一个元素。有一个指针指向当前集合头部的上一个空位
- void remove():删除。移除
next
指向的那个元素,需要与其连用 - 可以使用ForEach
public class Chap01 {
public static void main(String[] args) {
iteratorText();
}
public static void iteratorText(){
List<Integer> list = new ArrayList<>();
list.add(1); list.add(2); list.add(3);
// 生成一个迭代器
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()){ // 判断是否存在下一个
Integer next = iterator.next(); // 指针下移,取值
System.out.println(next);
}
}
}
LinkedList:可以作为
List
使用,也可以作为Deque
使用
public static void linkedListTest(){
// implements List<E>, Deque<E>, Cloneable, java.io.Serializable
// 实现了 Deque,相当于可以用队列/栈的方式来操作LinkedList
Deque<Integer> list = new LinkedList<>();
list.addFirst(2);
System.out.println(list.peek()); // 找到头元素
System.out.println(list.poll()); // 找到并移除头元素
list.addAll(Arrays.asList(3, 4, 6, 9)); // 添加多个元素
System.out.println(list.element()); // 找到头元素
list.offer(10); // 插入到最后
for (Integer integer : list) {
System.out.print(integer + "\t");
}
System.out.println(list.pop()); // 弹出
list.push(12); // 压入
}
ArrayList(基于jdk8)
- 底层使用
Object
数组存储 - 使用无参构造,初始容量为0,第一次调用
add
方法时,才初始化容量为10 - 使用有参构造,直接创建指定容量的数组
- 都是扩容为原来的1.5倍
- 可以重复添加
null
值
// 部分源码
private static final int DEFAULT_CAPACITY = 10; // 初始容量,当调用add方法是才会初始化
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData; // 使用的是Object数组存储
// 无参构造
public ArrayList() { // 初始容量为0
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
// 有参构造
public ArrayList(int initialCapacity) { // 指定初始容量
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
// add方法
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // 检测并初始化容量,默认为10
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
// 初始化容量
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
? 0 : DEFAULT_CAPACITY; // 如果是无参构造实例化的对象
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
// 扩容机制
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
// 扩容为原来的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
Vector:与
ArrayList
相同,添加了同步机制synchronied
,扩容为原来的两倍
LinkedList
- 底层实现了双向链表和双端队列特点
- 底层维护了一个双向链表,还维护了两个属性first和last分别指向首结点和尾结点
- 每个节点,里面又维护了prev、next、item三个属性
HashSet
- 实例化一个
HashSet
,其实底层实例化了一个HashMap
- 可以存放
null
值 - 第一次
add
时,才初始化容量为16 - 每次扩容为原来的两倍
- 最初是数组存储,当一个存在多个hash值相同,
equals
不同时,会在当前数组位置建立一条链表存储,当该链表的长度超过了8时,就会将链表改成红黑树来存储
// HashMap的部分源码
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 初始化容量 16
// 用于计算临界值,当 容量 * 加载英子 <= 当前数据 时,就会扩容
static final float DEFAULT_LOAD_FACTOR = 0.75f; // 加载英子
static final int TREEIFY_THRESHOLD = 8; // 一个位置上的链表阈值,当超过了这个阈值,就会使用红黑树来存储
static final int UNTREEIFY_THRESHOLD = 6; // 红黑树的阈值,将红黑树转为链表
LinkedHashSet:底层是一个LInkedHashMap,维护了一个数组+双向链表
TreeSet:保证了插入元素的有序
- 自然排序:
Comparable
接口,该接口里定义了一个compareTo
方法。使用类去实现该接口 - 定制排序:
Comparator
接口,该接口包含一个compare
方法,重写该方法,可以使用匿名
// 自然排序
public class Chap02 {
public static void main(String[] args) {
TreeSet<Student> treeSet = new TreeSet<>();
treeSet.add(new Student("丰1", 18));
treeSet.add(new Student("丰1", 17));
treeSet.add(new Student("丰", 17));
// [Student{name='丰', age=17}, Student{name='丰1', age=17}, Student{name='丰1', age=18}]
System.out.println(treeSet); // 升序
}
}
class Student implements Comparable<Student>{
// 实现Comparable接口,自然排序
private String name;
private int age;
// 实现compareTo方法
@Override
public int compareTo(Student o) {
// 模拟age排序
if (this.age > o.age){
return 1;
}else if (this.age < o.age){
return -1;
}else{ // 如果相同,可以使用二重排序
// String 实现了compareTo方法,这里调用的是String的
if (this.name.compareTo(o.name) > 0){
return 1;
}else if (this.name.compareTo(o.name) < 0){
return -1;
}
return 0;
}
}
} // 省略代码
// 定制排序
public class Chap03 {
public static void main(String[] args) {
// 定制排序,实现Comparator接口,重写compare方法
TreeSet<Persons> treeSet = new TreeSet<>(new Comparator<Persons>() {
@Override
public int compare(Persons o1, Persons o2) {
if (o1.getAge() > o2.getAge()){
return 1;
}else if (o1.getAge() < o2.getAge()){
return -1;
}else return 0;
}
});
treeSet.add(new Persons("丰1", 18));
treeSet.add(new Persons("丰1", 17));
treeSet.add(new Persons("丰", 17));
// [Persons{name='丰1', age='17'}, Persons{name='丰1', age='18'}]
// 因为不可重复,第三个就没有添加进去
System.out.println(treeSet);
}
}
class Persons{
private String name;
private int age;
}
Hashtable
- 线程安全
- 初始化容量为11
- 扩容为原来的 2倍 + 1
- 键不允许为
null
,而HashMap
可以
Collections工具类
void reverse(List list) // 倒序
void shuffle(List list) // 随机排序
void sort(List list) // 按自然排序的升序
void sort(List list, Comparator c) // 定制排序,由Comparator控制排序逻辑
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进行二分查找
int max(Collection coll)
int min(Collection coll, Comparator c)
void fill(List list, Object obj) // 用指定的元素代替指定list中的所有元素
int frequency(Collection c, Object o) // 统计元素出现次数
boolean replaceAll(List list, Object oldVal, Object newVal) // 用新元素替换旧元素