Java 集合学习笔记:Collection
Posted 笑虾
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 集合学习笔记:Collection相关的知识,希望对你有一定的参考价值。
Java 集合学习笔记:Collection
UML
简介
Collection
表示包含了一组元素
的对象
,它定义了一系列用来折腾这些元素
的方法。给徒子徒孙们立好了规矩。
通常不直接实现这个接口,而是实现它的两个徒弟 List、Set。
除非你要定义的是一个包含重复元素的无序 collection 。
方法和说明
限定符和类型 | 方法和说明 |
---|---|
boolean | add(E e) 确保此 collection 包含指定的元素(可选操作)。 |
boolean | addAll(Collection<? extends E> c) 将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。 |
void | clear() 移除此 collection 中的所有元素(可选操作)。 |
boolean | contains(Object o) 如果此 collection 包含指定的元素,则返回 true。 |
boolean | containsAll(Collection<?> c) 如果此 collection 包含指定 collection 中的所有元素,则返回 true。 |
boolean | equals(Object o) 比较此 collection 与指定对象是否相等。 |
int | hashCode() 返回此 collection 的哈希码值。 |
boolean | isEmpty() 如果此 collection 不包含元素,则返回 true。 |
Iterator<E> | iterator() 返回在此 collection 的元素上进行迭代的迭代器。 |
boolean | remove(Object o) 从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。 |
boolean | removeAll(Collection<?> c) 移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。 |
boolean | retainAll(Collection<?> c) 仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。 |
int | size() 返回此 collection 中的元素数。 |
Object[] | toArray() 返回包含此 collection 中所有元素的数组。 |
<T> T[] | toArray(T[] a) 返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同。 |
JDK8 新增 default
方法
限定符和类型 | 方法和说明 |
---|---|
default boolean | boolean removeIf(Predicate<? super E> filter) 删除此集合中满足给定谓词的所有元素。遍历中删除元素的求星。 |
default Stream | Stream<E> stream() 返回以此集合为源的顺序流。 |
default Stream | Stream<E> parallelStream() 返回以此集合为源的可能并行的流。 |
default Spliterator | Spliterator<E> spliterator() 在此集合中的元素上创建可拆分器迭代器。 |
AbstractCollection
抽象类 AbstractCollection 实现了一部分 Collection
isEmpty
因为此时还不知道底层实现类会使用什么数据结构,所以这里的size()
是抽象的,留给子类去实现。
public boolean isEmpty()
return size() == 0;
contains(Object o)
- 取迭代器,然后遍历所有元素,逐个判断如果发现与
给定元素
相等的,就返回true
给定元素
如果为null
使用==
判断是否相等,否则使用equals
。
public boolean contains(Object o)
Iterator<E> it = iterator();
if (o==null)
while (it.hasNext())
if (it.next()==null)
return true;
else
while (it.hasNext())
if (o.equals(it.next()))
return true;
return false;
toArray
toArray()
返回包含此 collection
中所有元素的数组。如果 collection
对其迭代器返回的元素顺序做出了某些保证,那么此方法必须以相同的顺序返回这些元素。
返回的数组将是“安全的
”,因为此 collection
并不引用返回的数组。(换句话说,即使 collection
底层实现就是数组,此方法也必须分配一个新的数组)。因此,调用者可以随意修改返回的数组。
此方法充当了基于Array API
与 基于collection API
之间的桥梁。
此实现返回一个数组,它包含此 collection
的迭代器返回的所有元素,这些元素的排列顺序与数组的连续元素存储顺序相同,都是从index 0
开始。返回数组的长度等于迭代器返回的元素数,即使此 collection
的大小发生更改也是如此,这种情况可能发生在 collection
允许在迭代期间进行并发修改
的时候。size
方法只是作为一个优化提示被调用;即使迭代器返回不同的元素数,也会返回正确的结果。
此方法等效于:
List<E> list = new ArrayList<E>(size());
for (E e : this)
list.add(e);
return list.toArray();
- 以当前集合
size
创建数组r
。(后续会多退少补) - 遍历数组
r
,每次从迭代器it
中取一个元素,填充到数组r
中。
2.1. 如果迭代器 < 数组
迭代器到头后,将数组r
复制一份,返回新数组。
2.2. 否则如果:数组r
遍历完,迭代器也正好取完,则返回数组r
。
2.3. 否则如果:数组r
遍历完,迭代器还有元素,则调用finishToArray
扩容数组r
继续填充。
public Object[] toArray()
// 暂时用集合 size 创建数组。多了少了后面会处理的。
Object[] r = new Object[size()];
// 获取迭代器
Iterator<E> it = iterator();
// 循环数组 r 的长度。每次从迭代器 it 中返回一个结果填进数组 r
// 如果填充到一半,迭代器已经完了,数组还没填满。
// 则直接将数组 r 内容复制到【新数组】并返回。
for (int i = 0; i < r.length; i++)
if (! it.hasNext()) // 元素比预期的少(迭代器到头了,数组还没填满)
return Arrays.copyOf(r, i);
r[i] = it.next();
// 如果数组 r 填满了,迭代器还有内容 ,则调用 finishToArray 继续处理。
return it.hasNext() ? finishToArray(r, it) : r;
private static <T> T[] finishToArray(T[] r, Iterator<?> it)
// 取数组后的长度。(也是填充新元素的索引的位置)
int i = r.length;
// 迭代器继续遍历
while (it.hasNext())
// 取数组 r 当前长度为:容积(下面有扩容操作,所以这里每次都要获取更新)
int cap = r.length;
// 判断数组中【元素个数 i】与【容积 cap】如果相等,说明没空间了,就扩容数组 r。
// 第一次执行到这,肯定是相等的。但数组扩容后,下一次再到这里【元素个数 i】就小于【容积 cap】了。
// 每次向数组填充数据【元素个数 i】就+1,一直循环到下一次 i == cap 再次触发扩容。
if (i == cap)
// 新容积 = 容积 + (容积 / 2 ) + 1
int newCap = cap + (cap >> 1) + 1;
// 对于溢出情况的处理
if (newCap - MAX_ARRAY_SIZE > 0) newCap = hugeCapacity(cap + 1);
// 复制数组 r 内容,并扩容到原 r 的 1.5 倍。
r = Arrays.copyOf(r, newCap);
// 迭代器中取出元素,填充到数组 r 的索引 i
r[i++] = (T)it.next();
// 去掉自动扩容多出来的位置。即:复制数组 r 第 0 到 i 的元素到新数组并返回。
return (i == r.length) ? r : Arrays.copyOf(r, i);
// 容器尺寸过小,报错,过大就返回最大值。
private static int hugeCapacity(int minCapacity)
if (minCapacity < 0)
throw new OutOfMemoryError("Required array size too large");
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
toArray(T[] a)
可以看作是 toArray()
的升级版,用于指定返回数组的元素类。
- 返回数组的类型,与给定的数组
a
一样。 - 如果我们给的数组
a
尺寸够用,则直接向a
中填充数据。 - 所以我们可以估计好数组大小,创建
a
时直接指定大小,能省去扩容的消耗。
public <T> T[] toArray(T[] a)
// 取当前 collection 大小,作为参考值。
int size = size();
// 如果给定的数组 a 够,就直接用 a, 否则创建一个新数组 r(类型为 T)接收数据。
T[] r = a.length >= size ? a :(T[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
Iterator<E> it = iterator();
for (int i = 0; i < r.length; i++)
// 如果迭代器已经到头了。
if (! it.hasNext()) // fewer elements than expected
// 使用的就是给定数组 a ,将当前索引位置都设为 null
if (a == r)
r[i] = null; // null-terminate
// 如果数组 a 长度小于已填充的元素个数 ,复制 r 到新数组并返回
else if (a.length < i)
return Arrays.copyOf(r, i);
// 如果给定的数组 a 够大,将 r 中数据复制到 a 并返回,末尾空位都填充 null
else
System.arraycopy(r, 0, a, 0, i);
if (a.length > i)
a[i] = null;
return a;
// 从迭代器取出元素填进数组 r
r[i] = (T)it.next();
// 如果数组填满,还没放完,扩容数组,继续填充。同 toArray()
return it.hasNext() ? finishToArray(r, it) : r;
add(E e)
实现了个寂寞。直接抛锅不支持的操作异常
。
public boolean add(E e)
throw new UnsupportedOperationException();
remove(Object o)
- 获取迭代器,遍历所有元素。
- 目标元素 o 为 null 时使用
==
判断,否则使用equals
。 - 删除操作,调用迭代器的
remove()
实现。
public boolean remove(Object o)
Iterator<E> it = iterator();
if (o==null)
while (it.hasNext())
if (it.next()==null)
it.remove();
return true;
else
while (it.hasNext())
if (o.equals(it.next()))
it.remove();
return true;
return false;
containsAll(Collection<?> c)
遍历给定集合 c
的每个元素,判断它是否包含在当前集合 this
中。
只要 c
中有一个元素,不被 this
包含,就返回 false
。
否则 c
中每个元素在当前集合中都存在,表示当前集合完全包含给定集合 c
public boolean containsAll(Collection<?> c)
for (Object e : c)
if (!contains(e))
return false;
return true;
addAll(Collection<? extends E> c)
- 遍历给定集合
c
逐个向当前this
集合中添加。 - 开头申明了一个
modified
标记编辑状态。只要for
中的add
操作成功一次,就更新为true
。
public boolean addAll(Collection<? extends E> c)
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
removeAll(Collection<?> c)
- 如果给定集合
c
为null
抛锅。 - 申明一个
modified
标记编辑状态。只要while
中的remove
操作成功一次,就更新为true
。 - 删除操作,底层通过当前集合的迭代器实现。
- 只要给定集合
c
包含迭代器next()
返回的对象,则执行remove
操作。
public boolean removeAll(Collection<?> c)
Objects.requireNonNull(c);
boolean modified = false;
Iterator<?> it = iterator();
while (it.hasNext())
if (c.contains(it.next()))
it.remove();
modified = true;
return modified;
retainAll(Collection<?> c)
与 removeAll
相反,c
不包含 next()
返回的对象就删除。(即:包含就保留)
public boolean retainAll(Collection<?> c)
Objects.requireNonNull(c);
boolean modified = false;
Iterator<E> it = iterator();
while (it.hasNext())
if (!c.contains(it.next()))
it.remove();
modified = true;
return modified;
clear()
获取迭代器,逐个删除。
public void clear()
Iterator<E> it = iterator();
while (it.hasNext())
it.next();
it.remove();
toString()
- 获取迭代器,判断如果没内容就返回字符串
[]
。 - 创建
StringBuilder
将每个元素添加进去。直到所有元素添加完sb.toString();
public String toString()
Iterator<E> it = iterator();
if (! it.hasNext())
return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;)
E e = it.next();
sb.append(e == this ? "(this Collection)" : e);
if (! it.hasNext())
return sb.append(']').toString();
sb.append(',').append(' ');
参考资料
Collection 单列集合(单值)
以上是关于Java 集合学习笔记:Collection的主要内容,如果未能解决你的问题,请参考以下文章
尚硅谷_Java零基础教程(集合Collection:list,set;map)-- 学习笔记