实现此接口允许对象成为可执行forEach目标。从类中三个方法可以看出实现Iterable接口可以获取到3种迭代元素的方法。
......
public interface Iterable {
// 返回泛型的顺序迭代器
Iterator iterator();
// 对Iterable中的元素进行指定的操作(1.8新添加的方法)
default void forEach(Consumer super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
// 返回一个内部元素为T类型的并行迭代器(1.8新添加的方法)
default Spliterator spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
迭代器。定义集合迭代器的通用方法和默认实现。常规用法循环调用hasNext()方法判断是否有下一个元素,有则调用next()方法获取下一个元素对象执行对应的操作。在1.8版本添加了forEachRemaining(),迭代所有剩余元素并执行给定的操作。
......
public interface Iterator {
/** 判断是否有下一个元素 */
boolean hasNext();
/** 返回下一个元素 */
E next();
/** 删除当前元素,默认抛出异常 */
default void remove() {
throw new UnsupportedOperationException("remove");
}
/** 根据当前迭代器的指针迭代剩余元素,并执行给定的操作(1.8新添加)
每次调用next()方法时,迭代器指针就会向后移动指向下一个元素,
而调用forEachRemaining()方法时会从当前指针进行迭代 */
default void forEachRemaining(Consumer super E> action) {
Objects.requireNonNull(action);
while (hasNext()) {
action.accept(next());
}
}
}
从语法上来讲集合的顶级父类是Iterabled,但实现Iterable只是获得迭代的功能,而Collection接口定义了集合常用的操作方法,值得注意的是Collection中也对子类进行了约定,所有通用Collection实现类(通常通过其子接口之一间接实现集合)都应提供两个“标准”构造函数:
一个无参数构造函数,它创建一个空集合。
另一个构造函数具有Collection类型的单个参数,它将创建一个具有与其参数相同元素的新集合。实际上,后一个构造函数允许用户复制任何集合,从而生成所需实现类型的等效集合。无法强制执行此约定(因为接口不能包含构造函数),但Java平台库中的所有通用Collection实现都符合此约定。
接口注释中还提示:此接口中包含的“破坏性”方法,即修改其操作的集合的方法,如果此集合不支持该操作,则指定为抛出UnsupportedOperationException。如果调用对集合没有影响,则这些方法可能(但不是必需)抛出UnsupportedOperationExceptio。
public interface Collection extends Iterable {
/** 集合元素数量 */
int size();
/** 是否空集合 */
boolean isEmpty();
/** 判断是否包含指定元素 */
boolean contains(Object o);
/** 获取集合迭代器 */
Iterator iterator();
/** 将集合转为数组 */
Object[] toArray();
/** 将集合元素按指定类型返回该类型的数组 */
T[] toArray(T[] a);
/** 添加元素 */
boolean add(E e);
/** 删除元素 */
boolean remove(Object o);
/** 判断是否包含所有元素 */
boolean containsAll(Collection> c);
/** 添加所有元素 */
boolean addAll(Collection extends E> c);
/** 删除多个给定的元素 */
boolean removeAll(Collection> c);
/** 删除此集合中满足给定过滤条件的所有元素 @since 1.8 */
default boolean removeIf(Predicate super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
/** 仅保留此集合中包含在参数集合中的元素,不包含的删除。 */
boolean retainAll(Collection> c);
/** 删除此集合中的所有元素。此方法返回后,集合将为空。 */
void clear();
/** 判断与指定对象是否相等 */
boolean equals(Object o);
/** 返回该集合的hashCode值,重写equals()方法必须重写hashCode()方法 */
int hashCode();
/** 默认实现从集合中获取可拆分迭代器,Spliterator是为了并行执行而设计的 @since 1.8 */
@Override
default Spliterator spliterator() {
return Spliterators.spliterator(this, 0);
}
/** 默认实返回顺序的Stream,@since 1.8 */
default Stream stream() {
return StreamSupport.stream(spliterator(), false);
}
/** 默认实现从集合的Spliterator创建一个并行的Stream。@since 1.8 */
default Stream parallelStream() {
return StreamSupport.stream(spliterator(), true);
}
}
AbstractCollection是一个抽象类,提供Collection部分接口的实现。主要对add和remove类型方法进行了实现,但是add()和remove()直接抛出UnsupportedOperationException异常,表示了默认实现不支持元素增删的操作,也就是默认集合不可修改。
要实现一个不可修改的集合,程序员只需要扩展这个类,并为iterator()和size()方法提供实现(迭代器方法返回的迭代器必须实现hasNext()和next()。
要实现可修改的集合,程序员必须另外重写这个类的add(E)方法(否则会抛出UnsupportedOperationException),而iterator()方法返回的迭代器必须另外实现remove()方法;
根据Collection接口规范中的建议,程序员通常应提供无参数构造方法和集合参数构造方法的实现。
......
// AbstractCollection实现add(E)方法直接抛出异常
public boolean add(E e) {
throw new UnsupportedOperationException();
}
public boolean remove(Object o) {
Iterator it = iterator();
if (o==null) {
while (it.hasNext()) {
if (it.next()==null) {
// 使用迭代器默认的删除逻辑
// 也就是抛出UnsupportedOperationException异常
it.remove();
return true;
}
}
}
......
return false;
}
通过Collections. unmodifiableCollection(Collection c) 方法就可以获得一个UnmodifiableCollection集合,此类中的增删改方法都是抛出UnsupportedOperationException异常,实现不可修改集合。
有序集合(也称为序列)。用户可以精确控制每个元素在列表中的插入位置。用户可以通过其整数索引(列表中的位置)访问元素,并在列表中搜索元素。列表通常允许重复元素。
List继承了Collection接口,并针对有序性定义了一些基于索引操作的方法。
public interface List extends Collection {
/** 从指定索引位置添加元素集合 */
boolean addAll(int index, Collection extends E> c);
/** 将集合中的所有元素执行给定的操作,例如所有字符串大小写转化等 @since 1.8 */
default void replaceAll(UnaryOperator operator) {
Objects.requireNonNull(operator);
final ListIterator li = this.listIterator();
while (li.hasNext()) {
li.set(operator.apply(li.next()));
}
}
/** 将集合元素按照给定的排序方式排序 @since 1.8 */
@SuppressWarnings({"unchecked", "rawtypes"})
default void sort(Comparator super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}
/** 获取指定索引位置的元素 */
E get(int index);
/** 设置索引位置的元素 */
E set(int index, E element);
/** 在指定索引位置添加元素 */
void add(int index, E element);
/** 获取元素的索引位置 */
int indexOf(Object o);
/** 获取元素最后出现的索引位置 */
int lastIndexOf(Object o);
/** 获取ListIterator迭代器,ListIterator是一种列表迭代器,
允许程序员沿任意方向遍历列表,在迭代期间修改列表,并获取迭代器在列表中的当前位置 */
ListIterator listIterator();
/** 获取指定索引位置的ListIterator迭代器 */
ListIterator listIterator(int index);
/** 根据给定的索引位置获取元素集合 */
List subList(int fromIndex, int toIndex);
}
AbstractList是一个抽象类,继承AbstractCollection并实现了List部分接口的实现,默认实现支持“随机访问”数据存储(如数组)的操作,随机访问即可通过索引访问任意一个元素。
要实现一个不可修改的列表,程序员只需要扩展这个类并为get(int)和size()方法提供实现即可。
要实现可修改列表,程序员必须另外重写set(int,Object)、set(int、E)方法(否则会引发UnsupportedOperationException异常)。如果列表大小可变,则程序员必须另外重写add(int,Object)、add(int、E)和remove(int)方法。l
根据Collection接口规范中的建议,程序员通常应提供无参数构造方法和集合参数构造方法的实现。
AbstractList是一个抽象类,继承AbstractList抽象了,并提供了List部分接口的实现,默认实现支持“顺序访问”数据存储(如链表)的操作,顺序访问即只能按照链表从头到尾或从尾到头的访问。
要实现一个列表,程序员只需要扩展这个类,并为listIterator()和size()方法提供实现即可。
要实现不可修改的列表,程序员只需实现列表迭代器的hasNext()、next(),hasPrevious()和previous()以及previousIndex()方法。
要实现可修改的列表,程序员应该另外实现列表迭代器的set方法。对于可变大小的列表,程序员应该另外实现列表迭代器的remove()和add(E)方法。
根据Collection接口规范中的建议,程序员通常应提供无参数构造方法和集合参数构造方法的实现。
ArrayList继承AbstractList并实现List接口,是Java中比较常用的有序、线程不安全集合,底层数据结构是Object数组,所以能够根据索引进行查询元素查询效率高。但增删效率较低,新增时可能导致底层数组扩容且复制数组,删除时会导致后面的元素进行位移。结合ArrayList的特点一般使用在查询多增删少的场景。
.....
public class ArrayList extends AbstractList
implements List, RandomAccess, Cloneable, java.io.Serializable {
/** 底层就是数组 */
transient Object[] elementData;
/** 默认数组初始长度是10 */
private static final int DEFAULT_CAPACITY = 10;
/** 记录当前集合内的元素个数 */
private int size;
/** 继承AbstractList而来,记录当前集合被修改的次数
每次add或者remove它的值都会加1 */
private transient int modCount = 0;
// 无参数构造方法只会创建一个空数组(除非)
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
// 添加元素方法
public boolean add(E e) {
// 验证元素个数+1是否超出数组长度
// 超出就进行扩容
ensureCapacityInternal(size + 1);
// size++
elementData[size++] = e;
return true;
}
// ArrayList扩容方法
private void grow(int minCapacity) {
// 记录原数组大小
int oldCapacity = elementData.length;
// oldCapacity >> 1 == oldCapacity / 2 每次扩容原数组大小1.5倍,
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 如果扩容后的大小比限制的数组最大值还要大
if (newCapacity - MAX_ARRAY_SIZE > 0)
// 将原大小与限制最大值进行比较,大于限制值就取Integer.MAX_VALUE
// 否则取限制最大值 Integer.MAX_VALUE - 8
newCapacity = hugeCapacity(minCapacity);
// 根据扩容的大小创建一个新数组,并把元素复制到新数组
elementData = Arrays.copyOf(elementData, newCapacity);
}
// 删除指定索引元素的方法
public E remove(int index) {
// 校验是否索引越界
rangeCheck(index);
// 集合修改次数加1
modCount++;
// 获取要删除的元素作为返回值
E oldValue = elementData(index);
// 计算出删除元素后要拷贝元素个数
// 例:当前elementData=["a","b","c","d"],我们要删除索引为1的元素也就是b
// numMoved = 4 - 1 - 1 = 2;也就是删除b后需要拷贝2个元素(c和d)
int numMoved = size - index - 1;
if (numMoved > 0)
// index+1就是从哪个索引开始拷贝,1+1=2也就是从索引2开始拷贝(c)
// index是要从哪个索引开始填充,也就是索引1的位置开始填充,
// numMoved拷贝个数
// 最终拷贝elementData=["a","c","d","d"]
// 其实简单来讲就是把要删除索引后的元素往前挪一位
System.arraycopy(elementData,index+1,elementData,index,numMoved);
// 将最后一个元素设置为null
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
private class Itr implements Iterator {
// 记录迭代时下一个元素的索引
int cursor;
// 记录next获取元素的索引
int lastRet = -1;
// 记录创建迭代器时当前集合修改的次数
int expectedModCount = modCount;
// 每次add和remove时都要判断记录的修改次数和当前集合的修改次数是否一致
// 如果不一致代表在迭代过程中集合已经被修改过了就会抛出异常
// 建议不要在迭代集合时add或remove元素
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
.....
}
LinkedList继承AbstractSequentialList并实现List接口,是Java中常用的有序、线程不安全的双向链表集合。底层使用内部类Node实现,每个Node都记录了上一个和下一个元素对象。新增只需要修改头或尾元素中记录的上或下一个元素即可。删除只需要修改相邻Node中记录的上下元素即可。所以增删效率高。但根据索引获取元素时都需要从头或尾(index LinkedList还实现了Deque接口,可以当做双端队列来使用,addFirst(E)、addLast(E)队列头、尾插入元素,pollFirst()、pollLast()检索并移除头、尾元素,peekFirst()、peekLast()检索不移除头、尾元素等队列操作。 Vector整理结构和内部实现类似ArrayList,继承AbstractList抽象类并实现List接口。但Vector中每个可能出现线程安全的方法上加了synchronized关键字,效率低,所以Vector是有序、线程安全的集合。正因为都是在方法上使用synchronized实现线程安全,所以还是会产生一些安全问题,已经不推荐使用。 综上来说推荐使用Collections.synchronizedList(List 集合中不包含重复元素,并且最多包含一个null元素是Set最主要的特性,对于是否有序来说默认是无序的,但直接继承了Collection接口并且没有添加新的方法定义。 AbstractSet是个抽象类,继承AbstractCollection抽象类同时实现Set接口,在此类只实现了equals()、hashCode()以及removeAll()方法。 虽然继承AbstractCollection类但是没有实现add()和remove()方法,所以默认还是一个不可修改的Set集合。如果想实现一个可修改Set集合,那么就需要重写add()和remove()方法。 但值得注意的是所有通过继承该类实现Set类型集合,那么所有子类中的所有方法和构造函数都必须遵守Set接口施加的附加约束元素不可重复且只能保存一个null值。 SortedSet继承了Set接口,并定义了comparator()方法,使得该类的子类都要实现此方法返回一个Comparator元素比较器,如果集合中的元素已经实现了Comparable中compareTo(T o)方法,那么可以在comparator()方法返回null,就会默认使用元素的compareTo(T o)方法。集合的迭代器将按升序元素顺序遍历集合。 NavigableSet是继承SortedSet接口,并扩展了相应的导航方法,通过指定元素搜索目标的最接近匹配项。 HashSet继承AbstractSet并实现Set接口,是无序、元素不可重复、线程不安全的集合。底层使用HashMap进行实现元素的唯一,即将元素作为Map的key进行保存。 TreeSet是继承AbstractSet并实现NavigableSet的Set集合。保留了Set集合元素不可重复的原则,且通过实现NavigableSet使得元素按照比较器进行排序。但值得注意的是TreeSet底层使用TreeMap进行实现,且元素排序也是通过TreeMap中的comparator比较器进行比较的,而TreeMap无参数构造方法默认comparator=null,所以在使用TreeSet前一定要保证所保存的元素类实现Comparable接口中compareTo(T o)方法,或者在创建TreeSet时传入Comparator比较器对象才能保证操作时对元素进行排序,所以TreeSet不允许null元素。 LinkedHashSet继承HashSet并实现Set接口,默认初始大小是16,创建时通过调用HashSet为其单独提供的构造方法使得LinkedHashSet底层使用LinkedHashMap实现。所以LinkedHashSet是一个有序(记录插入顺序)、不可重复、线程不安全的Set集合。 List有序的,按照索引(ArrayList)或者插入顺序(LinkedList)进行排序;Set可以是无序、指定排序规则进行排序(TreeSet)、插入顺序进行排序(LinkedHashSet); List集合元素可重复,Set集合元素不可重复; List在索引的加持下查询效率高,Set可确保元素不重复,两者适用不同场景。 Java.util.Collections是一个集合工具类,用于操作List,Set,Map等集合,并提供了一系列的静态方法,可以实现对集合元素的搜索、排序(自定义比较、混排、反转)、元素替换、复制、线程安全等操作。......
public class LinkedList
Vector
// 假如有两个线程同时进入contains(e)方法,传递的参数都是一样的,例如 contains("123")。
// 当线程1执行if (!vector.contains(element)) 后还没有执行vector.add(element); 时,
// 线程2进来了,此时vector.contains(element))还是返回false,
// 这样的结果会导致两个123都加入到vector。所以是线程不安全的。
if (!vector.contains(element))
vector.add(element);
}
......
public class Vector
Set
AbstractSet
SortedSet
......
public interface SortedSet
NavigableSet
......
public interface NavigableSet
HashSet
......
public class HashSet
TreeSet
......
public class TreeSet
LinkedHashSet
public class LinkedHashSet
List和Set的区别
Collections
/** 给定集合返回不可修改的集合方法 */
// 用给定的Collection作为参数创建UnmodifiableCollection不可修改的集合
static Collection unmodifiableCollection(Collection c);
// 用给定的List作为参数创建UnmodifiableList
// 或UnmodifiableRandomAccessList(实现RandomAccess接口的)不可修改的集合
static List unmodifiableList(List list);
// 用给定的Map作为参数创建UnmodifiableMap不可修改的Map
static Map unmodifiableMap(Map m);
// 用给定的NavigableMap作为参数创建UnmodifiableNavigableMap不可修改的NavigableMap
static NavigableMap unmodifiableNavigableMap(NavigableMap m);
// 用给定的NavigableSet作为参数创建UnmodifiableNavigableSet不可修改的NavigableSet
static NavigableSet unmodifiableNavigableSet(NavigableSet s);
// 用给定的Set作为参数创建UnmodifiableSet不可修改的Set。
static Set unmodifiableSet(Set s);
// 用给定的SortedMap作为参数创建UnmodifiableSortedMap不可修改的SortedMap。
// 底层使用Collections内部类
static SortedMap unmodifiableSortedMap(SortedMap m);
// 用给定的SortedSet作为参数创建UnmodifiableSortedSet不可修改的SortedSet
static SortedSet unmodifiableSortedSet(SortedSet s);
// 返回仅包含给定对象的不可变Set集合
static Set singleton(T o);
// 返回仅包含给定对象的不可变集合
static List singletonList(T o);
// 返回仅包含给定参数的不可变Map
static Map singletonMap(K key, V value);
/** 给定集合返回不可修改的集合方法 */
// 用给定的SortedSet创建SynchronizedSortedSet线程安全集合
static Collection synchronizedCollection(Collection c);
// 用给定的List创建SynchronizedList或SynchronizedRandomAccessList线程安全集合
static List synchronizedList(List list);
// 用给定的Map创建SynchronizedMap线程安全Map
static Map synchronizedMap(Map m);
// 用给定的NavigableMap创建SynchronizedNavigableMap线程安全NavigableMap
static NavigableMap synchronizedNavigableMap(NavigableMap m);
// 用给定的NavigableSet创建SynchronizedNavigableSet线程安全NavigableSet
static NavigableSet synchronizedNavigableSet(NavigableSet s);
// 用给定的Set创建SynchronizedSet线程安全Set
static Set synchronizedSet(Set s);
// 用给定的SortedMap创建SynchronizedSortedMap线程安全SortedMap
static SortedMap synchronizedSortedMap(SortedMap m);
// 用给定的SortedSet创建SynchronizedSortedSet线程安全SortedSet
static SortedSet synchronizedSortedSet(SortedSet s);
/** 排序 */
// 用给定列表中的元素旋转给定的距离。正数向后移动,负数向前移动,集合长度不变
static void rotate(List list, int distance);
// 根据由给定的比较器进行排序。
static void sort(List list, Comparator c);
// 交换给定列表中给定位置的元素。
static void swap(List list, int i, int j);
// 使用默认源随机性。
static void shuffle(List list);
// 使用给定的源随机排列给定的列表随机性。
static void shuffle(List list, Random rnd);
// 根据给定列表元素的自然顺序,按其升序对给定列表进行排序。元素必须实现Comparable接口
static void sort(List list);
/** 复制、替换 */
// 将所有元素从一个列表复制到另一个列表中。
static void copy(List dest, List src);
// 用给定列表的所有元素替换为给定的元素。
static void fill(List list, obj);
// 将列表中所有匹配oldVal项替换为newVal。
static boolean replaceAll(List list, oldVal, newVal);
/** 查询 */
// 返回给定对象在集合中的索引。
static int frequency(Collection c, Object o);
// 如果两个给定的集合没有相同的元素返回true
static boolean disjoint(Collection c1, Collection c2);
// 返回给定的第一个匹配项的起始位置 给定源列表中的目标列表,如果没有,则为 -1 这样的发生。
static int indexOfSubList(List source, List target);
// 返回给定 给定源列表中的目标列表,如果没有这样的目标列表,则为 -1 发生。
static int lastIndexOfSubList(List source, List target);
// 根据给定集合元素的自然顺序返回其最大元素。元素必须实现Comparable接口
static max(Collection coll);
// 返回给定集合的最大元素,根据由给定的比较器引起的阶次。
static max(Collection coll, Comparator comp);
// 根据给定集合元素的自然顺序返回其最小元素。元素必须实现Comparable接口
static min(Collection coll);
// 返回给定集合的最小元素,根据由给定的比较器引起的阶次。
static min(Collection coll, Comparator comp);