Java 集合学习笔记:Collection

Java 集合学习笔记:Collection

  • UML
  • 简介
    • 方法和说明
    • JDK8 新增 `default` 方法
  • AbstractCollection
    • isEmpty
    • contains(Object o)
    • toArray
      • toArray()
      • toArray(T[] a)
    • add(E e)
    • remove(Object o)
    • containsAll(Collection c)
    • addAll(Collection c)
    • removeAll(Collection c)
    • retainAll(Collection c)
    • clear()
    • toString()
  • 参考资料

UML

在这里插入图片描述

简介

Collection 表示包含了一组元素对象,它定义了一系列用来折腾这些元素的方法。给徒子徒孙们立好了规矩。
通常不直接实现这个接口,而是实现它的两个徒弟 List、Set。
除非你要定义的是一个包含重复元素的无序 collection 。

方法和说明

限定符和类型方法和说明
boolean add(E e)
确保此 collection 包含指定的元素(可选操作)。
boolean addAll(Collection 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 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[] toArray(T[] a)
返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同。

JDK8 新增 default 方法

限定符和类型方法和说明
default booleanboolean removeIf(Predicate filter)
删除此集合中满足给定谓词的所有元素。遍历中删除元素的求星。
default StreamStream stream()
返回以此集合为源的顺序流。
default StreamStream parallelStream()
返回以此集合为源的可能并行的流。
default Spliterator Spliterator spliterator()
在此集合中的元素上创建可拆分器迭代器。

AbstractCollection

抽象类 AbstractCollection 实现了一部分 Collection

isEmpty

因为此时还不知道底层实现类会使用什么数据结构,所以这里的size()是抽象的,留给子类去实现。

    public boolean isEmpty() {return size() == 0;}

contains(Object o)

  1. 取迭代器,然后遍历所有元素,逐个判断如果发现与给定元素相等的,就返回 true
  2. 给定元素如果为 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 list = new ArrayList(size());
for (E e : this)
list.add(e);
return list.toArray();

  1. 以当前集合size创建数组 r。(后续会多退少补)
  2. 遍历数组 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 ) + 1int 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 的索引 ir[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() 的升级版,用于指定返回数组的元素类。

  1. 返回数组的类型,与给定的数组 a 一样。
  2. 如果我们给的数组 a 尺寸够用,则直接向 a 中填充数据。
  3. 所以我们可以估计好数组大小,创建 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 ,将当前索引位置都设为 nullif (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;}// 从迭代器取出元素填进数组 rr[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)

  1. 获取迭代器,遍历所有元素。
  2. 目标元素 o 为 null 时使用 == 判断,否则使用 equals
  3. 删除操作,调用迭代器的 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 c)

  1. 遍历给定集合 c 逐个向当前 this 集合中添加。
  2. 开头申明了一个 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)

  1. 如果给定集合 cnull 抛锅。
  2. 申明一个 modified 标记编辑状态。只要 while 中的 remove 操作成功一次,就更新为 true
  3. 删除操作,底层通过当前集合的迭代器实现。
  4. 只要给定集合 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()

  1. 获取迭代器,判断如果没内容就返回字符串 []
  2. 创建 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 单列集合(单值)


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部