Collection接口
Collection是单个集合保存的最大父接口
Collection接口定义
public interface Collection<E> extends Iterable<E>
Collection接口的重要方法
取得集合长度:int size();
判断集合是否为空:boolean isEmpty();
查找数据是否存在(需要使用equals()方法):boolean contains(Object o);
将集合变为数组对象返回: T[] toArray(T[] a);
向集合中添加数据:boolean add(E e);
删除数据(需要equals()方法):boolean remove(Object o);
清空数据void clear();
取得Iterator接口对象,用于集合输出:Iterator<E> iterator();
Collection接口的两个子接口
List接口(允许保存重复数据)
List接口的f两个扩充方法
- 根据索引取得保存数据:public E get(int index);
- 修改数据:public E set(int index,E element);
List接口的三个实现类
ArrayList:JDK1.2(运用最多)
- 初始化策略:Lazy-load(懒加载策略),只有当Array对象第一次被使用(add)时,内部的数组才会初始化为长度为10的数
- 扩容:每次扩容为原先数组的1.5倍
- 线程安全性:线程不安全,但性能高
- 输出形式:支持迭代输出,(foreach编译之后的class文件本身也为迭代输出);
Vector:JDK1.0
- 初始化策略:当产生Vextor对象是,内部数组就初始化大小为10的数组
- 扩容:每次扩容为原先数组的2倍
- 线程安全性:使用synchronized同步方法来确保线程安全性,但性能低(读写互斥)
- 输出形式:叠带输出。枚举输出
特殊:JDK内置的Stack继承Vector类
LinkedListJDK1.2
- 基于双向链表的动态数组,线程不安全
特殊:JDK Queue的一个子类
ArrayList封装的是数组,LiinkedList封装的是链表,ArrayList时间复杂度为1,而LinkedList的复杂度为n
Set集合接口(不允许保存重复数据)
Set接口的常用子类
HashSet(无序存储)
底层实现:JDK1.8之前哈希表,1.8之后是哈希表和红黑树
HashSet使用equals与hashCode共同判断元素是否重复
- hashCode:对象在内存中的地址根据Hash算法转为int
- equals:判断两个对象属性是否相同
对象.equals与hashCode关系
- equals相同,hashCode一定返回相同
- hashCode相同,equals不一定相同
TreeSet(按照升序存储)
注意:不允许存放null
底层实现:红黑树
一个类要想使用TreeSet的两种方式
- 自己实现了Comparable
- 从外部传入一个该类的比较器对象(实现Comparator接口)
java.lang.Comparable : 内部排序接口
类实现了Comparable表示此类具备可比较的性质
int compareTo(T o);
> 0 : 大于目标对象
= 0 : 等于
< 0 : 小于目标对象
java.util.Comparator : 外部排序接口(最常使用) 策略模式
类本身不具备可比较的特性,专门有一个类来比较自定义类的大小
int compare(T o1, T o2);
TreeSet根据比较接口的返回值来判断两个元素是否重复
Collection的输出
迭代器输出
Iterator接口中的方法
- 判断当前集合是否还有未遍历的元素:boolean hasNext();
- 取得当前正在遍历的内容:E next();
取得该Collection接口对象的迭代器:Iterator<E> iterator();
输出格式(Scanner类也继承了Iterator接口)
while(iterator.hasNext()) {
E e = iterator.next();
}
foreach:语法糖(只存在于代码编译阶段)
Collection接口能采用foreach输出的本质在于,所有子类都实现了Iterator接口
ListIterator(双向迭代输出-只有List接口有)
- 判断当前集合是否还有上一个元素:boolean hasPrevious();
- 取得上一个元素:E previous();
注意:要想从后向前输出:必须先从前到后输出一次
Enumeration(枚举输出-只有Vector及其子类Stack才有)
- boolean hasMoreElements();
- E nextElement();
快速失败策略(fail-fast)
优先考虑异常情况,当异常情况发生时,直接向用户抛出异常,程序终止。fail-fast保证集合在多线程场景下读到正确的值
// 取得集合迭代器时的modCount值
int expectedModCountexpectedModCount = modCount;
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
java.util.的集合类大多都采用此策略(ArrayList、Vector、LinkedList、HashSet,读写都在同一个副本中)
CopyOnWriteArrayList采用读写分离,所有的读为异步操作,写为同步操作,且读写不在一个副本
如何避免ConcurrentModificationException
- 迭代输出的时候,不要修改集合的内容
- 使用迭代器的修改方法