简介

Collection继承自Iterable,Collection接口是Java集合两大分支中的一支,Queue、List、Set都是Collection的扩展;集合大类分为了Collection和Map。

常见的数据结构:数组(Array)、集(Set)、队列(Queue)、链表(Linkedlist)、树(Tree)、堆(Heap)、栈(Stack)和映射(Map)等结构

Iterable接口

实现这个接口的类允许使用 for-each loop 语句来遍历

public interface Iterable<T> {
// 返回一个迭代器对象
Iterator<T> iterator();
// JDK1.8 新增遍历方式
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
// 可分割迭代器
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}

Iterable最早出现在JDK 1.5,开始只有iterator()一个抽象方法,需要子类来实现一个内部迭代器Iterator遍历元素。
后两个方法是Java 8后新添加的,forEach(Consumer action)是为了方便遍历操作集合内的元素,Spliterator(splitable iterator可分割迭代器)接口是Java为了并行遍历数据源中的元素而设计的迭代器,这个可以类比最早Java提供的顺序遍历迭代器Iterator,但一个是顺序遍历,一个是并行遍历。

Collection 接口

Collection是一个高度封装的集合接口,它提供了所有集合要实现的默认方法  

public interface Collection<E> extends Iterable<E>

基本方法

// 返回此集合的元素数量
int size();
// 返回集合是否为空
boolean isEmpty();
// 如果包含元素O则返回为true
boolean contains(Object o);
// 返回此集合元素的迭代器
Iterator<E> iterator();
// 将此集合转化为数组
Object[] toArray();
// 将此集合转化为制定类型数组
<T> T[] toArray(T[] a);
// 返回值是boolean,添加一个元素
boolean add(E e);
// 删除指定的元素
boolean remove(Object o);
// 如果包含集合C返回为true
boolean containsAll(Collection<?> c);
// 返回值是boolean类型,将集合C中的所有元素添加到此集合
boolean addAll(Collection<? extends E> c);
// 删除包含集合c的所有元素
boolean removeAll(Collection<?> c);
// 获取集合c与此集合的交集
boolean retainAll(Collection<?> c);
// 删除此集合中的所有元素
void clear();
// 将指定的对象O与此集合进行比较
boolean equals(Object o);
// 返回此集合的INT类型哈希码
int hashCode();

默认实现方法

// 删除满足条件的所有元素
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
@Override
// 创建一个Spliterator
default Spliterator<E> spliterator() {
return Spliterators.spliterator(this, 0);
}
// 返回以此集合作为源的顺序流
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
// 创建一个Spliterator并行流
default Stream<E> parallelStream() {
return StreamSupport.stream(spliterator(), true);
}

AbstractCollection 抽象类

AbstractCollection 实现Collection接口,该类是一个抽象类,提供了对集合类操作的一些基本实现。List和Set的具体实现类基本上都直接或间接的继承了该类

public abstract class AbstractCollection<E> implements Collection<E>

构造函数

protected AbstractCollection() {
}

未实现的方法

// 获取迭代器
public abstract Iterator<E> iterator();
// 获取集合元素个数
public abstract int size();

已实现的方法

AbstractCollection所有已实现的方法子类都会覆盖掉,官方的说法 “此类提供集合的骨架实现接口,以最小化实现此接口所需的工作”

判空

public boolean isEmpty() {
// 元素个数为0,就为空
return size() == 0;
}

添加

public boolean add(E object) {
throw new UnsupportedOperationException();
}

public boolean addAll(Collection<? extends E> c) {
// 是否添加成功
boolean modified = false;
// 迭代参数中每一个元素
for (E e : c)
// 添加元素并判断是否添加成功
if (add(e))
modified = true;
// 返回是否添加成功
return modified;
}

直接调用AbstractCollection的add方法会抛出异常,所以我们在实现Collection自定义数据结构时一定要覆盖此方法。

删除

public boolean remove(Object object) {
//获取子类实现的 迭代器
Iterator<?> it = iterator();
if (object != null) { // 参数不为空
// 循环迭代
while (it.hasNext()) {
// 对比找到元素
if (object.equals(it.next())) {
// 移除
it.remove();
return true;
}
}
} else { // 参数为空
// 循环迭代,参数为空相当于清空
while (it.hasNext()) {
if (it.next() == null) {
// 移除
it.remove();
return true;
}
}
}
return false;
}

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;
}

清空

public void clear() {
// 获取子类实现的迭代器,挨个遍历,删除
Iterator<E> it = iterator();
// 循环迭代
while (it.hasNext()) {
it.next();
// 单线程使用迭代器的 remove() 方法不会导致 fail-fast
it.remove();
}
}

包含

public boolean contains(Object o) {
// 获取当前迭代器
Iterator<E> it = iterator();
if (o==null) { // 参数为空
// 迭代查找是否包含空元素
while (it.hasNext())
if (it.next()==null)
// 包含空返回true
return true;
} else {
// 迭代每一个元素进行比较
while (it.hasNext())
if (o.equals(it.next()))
// 元素equals相等返回true
return true;
}
return false;
}

public boolean containsAll(Collection<?> c) {
// 遍历参数中每一个元素
for (Object e : c)
// 有一个不包含就返回false
if (!contains(e))
return false;
// 能到这儿说明都包含
return true;
}

取交集

public boolean retainAll(Collection<?> collection) {
boolean result = false;
Iterator<?> it = iterator();
// 迭代当前集合
while (it.hasNext()) {
// 参数集合中不包含,就在当前集合中移除此元素
if (!collection.contains(it.next())) {
// 移除
it.remove();
// 移除成功,结果置为true
result = true;
}
}
return result;
}

转数组

public <T> T[] toArray(T[] a) {
// 获取集合长度
int size = size();
// 参数数组长度大于此集合长度就用参数数组,否则创建新数组
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
if (a == r) {
//如果数组是参数中的数组,则将剩余部分的值都设置为null
r[i] = null; // null-terminate
// 如果传入的数组长度小于集合长度
} else if (a.length < i) {
// 通过Arrays.copyOf将之前数组中的元素复制到新数组中
return Arrays.copyOf(r, i);
} else {//如果传入数组的长度比集合大,则将多的元素设置为空
System.arraycopy(r, 0, a, 0, i);
if (a.length > i) {
a[i] = null;
}
}
return a;
}
r[i] = (T)it.next();
}
// more elements than expected
//集合元素大小大于数组的长度
return it.hasNext() ? finishToArray(r, it) : r;
}
private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
// 获取新数组长度
int i = r.length;
// 接着前面继续迭代
while (it.hasNext()) {
int cap = r.length;
// 起始位置
if (i == cap) {
// 新数组扩容,新长度 = 原长度*2 + 1
int newCap = cap + (cap >> 1) + 1;
// 新长度小于上限(int最大值-8)
if (newCap - MAX_ARRAY_SIZE > 0)
newCap = hugeCapacity(cap + 1);
// 创建新数组并拷贝原数组
r = Arrays.copyOf(r, newCap);
}
// 下标加1继续放值
r[i++] = (T)it.next();
}
// 新数组
return (i == r.length) ? r : Arrays.copyOf(r, i);
}

private static int hugeCapacity(int minCapacity) {
// 长度小于0抛出越界异常
if (minCapacity < 0) // overflow
throw new OutOfMemoryError
("Required array size too large");
// 长度超限默认最大值
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}

对于toArray方法可能很多人会有疑问,toArray方法第二步如果数组长度不够不是已经建了新数组吗,为什么在迭代过程中还要对新数组进行扩容?

toArray不是线程安全的,在迭代的过程中,没有人能保证数据结构中元素不会增加或减少,减少到没关系,增加后新创建的数组放不下了怎么办?所以只能做扩容处理。

数据结构 - Collection接口的更多相关文章

  1. java中常用的数据结构--Collection接口及其子类

    java中有几种常用的数据结构,主要分为Collection和map两个主要接口(接口只提供方法,并不提供实现),而程序中最终使用的数据结构是继承自这些接口的数据结构类. 一.集合和数组的区别 二.C ...

  2. 集合中list、ArrayList、LinkedList、Vector的区别、Collection接口的共性方法以及数据结构的总结

    List (链表|线性表) 特点: 接口,可存放重复元素,元素存取是有序的,允许在指定位置插入元素,并通过索引来访问元素 1.创建一个用指定可视行数初始化的新滚动列表.默认情况下,不允许进行多项选择. ...

  3. 数据结构-List接口-LinkedList类-Set接口-HashSet类-Collection总结

    一.数据结构:4种--<需补充> 1.堆栈结构:     特点:LIFO(后进先出);栈的入口/出口都在顶端位置;压栈就是存元素/弹栈就是取元素;     代表类:Stack;     其 ...

  4. java 数据结构(七):Collection接口

    1.单列集合框架结构|----Collection接口:单列集合,用来存储一个一个的对象* |----List接口:存储序的.可重复的数据. -->“动态”数组* |----ArrayList. ...

  5. Java集合框架之Collection接口

    Java是一门面向对象的语言,那么我们写程序的时候最经常操作的便是对象了,为此,Java提供了一些专门用来处理对象的类库,这些类库的集合我们称之为集合框架.Java集合工具包位于Java.util包下 ...

  6. Java集合总结系列2:Collection接口

    Collection 接口是 Java 集合类的一个根接口,Java 在 Collection 接口中定义了许多通用的数据操作类方法以及判断类方法. 通过查看 API 文档或源码的方式,我们可以了解到 ...

  7. Java中集合框架,Collection接口、Set接口、List接口、Map接口,已经常用的它们的实现类,简单的JDK源码分析底层实现

    (一)集合框架: Java语言的设计者对常用的数据结构和算法做了一些规范(接口)和实现(实现接口的类).所有抽象出来的数据结构和操作(算法)统称为集合框架. 程序员在具体应用的时候,不必考虑数据结构和 ...

  8. linkin大话数据结构--Collection和Iterator

    linkin大话数据结构--Collection和Iterator Java 集合就像一种容器,可以把多个对象的引用放入容器中.Java 集合类可以用于存储数量不等的多个对象,还可用于保存具有映射关系 ...

  9. 基础常用的数据结构 Collection Map

    map是键值对的集合接口,它的实现类主要包括:HashMap,TreeMap,Hashtable以及LinkedHashMap等.其中这四者的区别如下(简单介绍): HashMap:我们最常用的Map ...

随机推荐

  1. Redmine it!

    redmine插件开发简介 最稳妥的学习应该是先看官方文档,官方还给了一个具体的插件开发教程,不过如果一步不差按照教程敲代码,其实会发现还是有些问题的,需要稍稍改动. 这里,我自己编写了一个简单的插件 ...

  2. MOOC(7)- case依赖、读取json配置文件进行多个接口请求-读取json封装成类(13)

    把读取json数据的函数封装成类 # -*- coding: utf-8 -*- # @Time : 2020/2/12 16:44 # @File : do_json_13.py # @Author ...

  3. 无标定量|有标定量|谱图计数|XIC|AMT数据库|RT对对齐|母离子|子离子|SILVER|SRM|iBAQ|APEX|差异蛋白筛选|MaxQuant|PANDA|C-HPP

    生物医学大数据-蛋白质定量 现今肽段定量效率存在巨大差异.比如相同质量蛋白质,但是肽段和蛋白信号不均一,在物理条件一致时,仅有70%的重复率,并且当重复次数变多时,overlapping在变少. 无标 ...

  4. laravel-事件

    1.注册事件以及监听器 首先我们需要在 app/Providers/目录下的EventServiceProvider.php中注册事件监听器映射关系,如下: /** * The event liste ...

  5. Python---12函数式编程------12.3匿名函数&装饰器&偏函数

    一.匿名函数 当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便. 在Python中,对匿名函数提供了有限支持.还是以map()函数为例,计算f(x)=x2时,除了定义一个f( ...

  6. wabpack踩坑

    webpack 打包时会用 NODE_ENV 来标识是生产环境还是开发环境光, "build": "NODE_ENV=production webpack", ...

  7. kNN算法 Demo

    项目链接: https://github.com/WES6/kNN

  8. 状态模式(State)-设计模式

    软件模式是将模式的一般概念应用于软件开发领域,即软件开发的 总体指导思路或参照样板.软件模式并非仅限于设计模式,还包括 架构模式.分析模式和过程模式等,实际上,在软件生存期的每一个阶段都存在着一些被认 ...

  9. 机器学习- RNN以及LSTM的原理分析

    概述 RNN是递归神经网络,它提供了一种解决深度学习的另一个思路,那就是每一步的输出不仅仅跟当前这一步的输入有关,而且还跟前面和后面的输入输出有关,尤其是在一些NLP的应用中,经常会用到,例如在NLP ...

  10. DotNet Core 使用 StackExchange.Redis 简单封装和实现分布式锁

    前言 公司的项目以前一直使用 CSRedis 这个类库来操作 Redis,最近增加了一些新功能,会存储一些比较大的数据,内测的时候发现其中有两台服务器会莫名的报错 Unexpected respons ...