collection
在java集合中,算是顶级接口,它继承了iterable
接口,不能实例化,只能实例化其子类。之所以需要这样一个接口,是因为java作为面向对象,总是避免不了处理多个对象的情况,要处理多个对象,首先需要容器存储,这个容器就是集合。为什么有了数组,还需要集合,因为数组的功能单一,长度不可变,而有些集合实现类则是对数组操作的封装。
Collection
集合和数组的区别:
Collection
继承于Iterable
接口,而Iterable
接口,是集合的顶级接口,没有之一,Iterable
接口定义的功能是可以迭代,也就是获取迭代器iterator
的功能,因此Collection
以及其实现类也间接获得迭代的功能。
为什么需要这样子定义呢?我陷入了深深地思考…????
其实,这也算是哲学问题,java的类的设计是经过很长时间的考验以及调整形成的,平衡修改以及耦合等各方面的原因,结构更加清晰,维护成本更低,逻辑性更强。这些接口就是一个个标准或者规范,其子类就是不断拓展功能,这些接口的形成是一种抽象,将能迭代事物抽象成为迭代器iterator
,将获取迭代器,也就是迭代能力抽象成iterable
。Collection
则是获得迭代能力的接口之一,其实Map
的实现类里面也是有使用到iterable
接口,几乎所有的集合实现类都是需要遍历元素的,所以这个iterable
也是必须存在的,存在即合理。
下面看Collection
接口以及iterable
接口的方法对比:
从上面的图我们可以看出,iterable
接口功能主要是
iterator
Spliterator
Collection
接口在此基础上进行拓展,源码接口如下:
boolean add(Object o) //添加元素boolean remove(Object o) //移除元素boolean addAll(Collection c) //批量添加boolean removeAll(Collection c) //批量移除void retainAll(Collection c) // 移除在c中不存在的元素void clear() //清空集合int size() //集合大小boolean isEmpty() //是否为空boolean contains(Object o) //是否包含在集合中boolean containsAll(Collection c) //是否包含所有的元素Iterator<E> iterator() // 获取迭代器Object[] toArray() // 转成数组default boolean removeIf(Predicate<? super E> filter) {} // 删除集合中复合条件的元素,删除成功返回trueboolean equals(Object o)int hashCode()default Spliterator<E> spliterator() {} //获取可分割迭代器default Stream<E> stream() {} //获取流default Stream<E> parallelStream() {} //获取并行流
里面获取并行流的方法parallelStream()
,其实就是通过默认的ForkJoinPool(主要用来使用分治法(Divide-and-Conquer Algorithm)来解决问题),提高多线程任务的速度。我们可以使用ArrayList来演示一下平行处理能力。例如下面的例子,输出的顺序就不一定是1,2,3…,可能是乱序的,这是因为任务会被分成多个小任务,任务执行是没有特定的顺序的。
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);list.parallelStream() .forEach(out::println);
上面源代码可以看出,Collection
接口定义了功能规范,有以下功能方法:
我们遍历元素的时候可以获取Iterator
,但是具体的实现是以子类的特性去实现的,比如ArrayList
是用内部类的方式实现了Iterator
接口。
继承Collection
的子类关系如下:
上面的类图已经足够清楚,下面是一些简单的概括(上面的类型是使用IDEA的类图功能自动生成,简直不能太好用????????????感觉发现了新大陆)
继承于Collection
接口,有顺序,取出的顺序与存入的顺序一致,有索引,可以根据索引获取数据,允许存储重复的元素,可以放入为null的元素。
最常见的三个实现类就是ArrayList
,Vector
,LinkedList
,ArrayList
和Vector
都是内部封装了对数组的操作,唯一不同的是,Vector
是线程安全的,而ArrayList
不是,理论上ArrayList
操作的效率会比Vector
好一些。
里面是接口定义的方法:
int size(); //获取大小boolean isEmpty(); //判断是否为空boolean contains(Object o); //是否包含某个元素Iterator<E> iterator(); //获取迭代器Object[] toArray(); // 转化成为数组(对象)<T> T[] toArray(T[] a); // 转化为数组(特定位某个类)boolean add(E e); //添加boolean remove(Object o); //移除元素boolean containsAll(Collection<?> c); // 是否包含所有的元素boolean addAll(Collection<? extends E> c); //批量添加boolean addAll(int index, Collection<? extends E> c); //批量添加,指定开始的索引boolean removeAll(Collection<?> c); //批量移除boolean retainAll(Collection<?> c); //将c中不包含的元素移除default void replaceAll(UnaryOperator<E> operator) {}//替换default void sort(Comparator<? super E> c) {}// 排序void clear();//清除所有的元素boolean equals(Object o);//是否相等int hashCode(); //计算获取hash值E get(int index); //通过索引获取元素E set(int index, E element);//修改元素void add(int index, E element);//在指定位置插入元素E remove(int index);//根据索引移除某个元素int indexOf(Object o); //根据对象获取索引int lastIndexOf(Object o); //获取对象元素的最后一个元素ListIterator<E> listIterator(); // 获取List迭代器ListIterator<E> listIterator(int index); // 根据索引获取当前的位置的迭代器List<E> subList(int fromIndex, int toIndex); //截取某一段数据default Spliterator<E> spliterator(){} //获取可切分迭代器
上面的方法都比较简单,值得一提的是里面出现了ListIterator
,这是一个功能更加强大的迭代器,继承于Iterator
,只能用于List
类型的访问,拓展功能例如:通过调用listIterator()
方法获得一个指向List开头的ListIterator
,也可以调用listIterator(n)
获取一个指定索引为n的元素的ListIterator
,这是一个可以双向移动的迭代器。
操作数组索引的时候需要注意,由于List的实现类底层很多都是数组,所以索引越界会报错IndexOutOfBoundsException
。
说起List的实现子类:
Set
接口,不允许放入重复的元素,也就是如果相同,则只存储其中一个。
下面是源码方法:
int size(); //获取大小boolean isEmpty(); //是否为空 boolean contains(Object o); //是否包含某个元素Iterator<E> iterator(); //获取迭代器Object[] toArray(); //转化成为数组<T> T[] toArray(T[] a); //转化为特定类的数组boolean add(E e); //添加元素boolean remove(Object o); //移除元素boolean containsAll(Collection<?> c); //是否包含所有的元素boolean addAll(Collection<? extends E> c); //批量添加boolean retainAll(Collection<?> c); //移除所有不存在于c集合中的元素boolean removeAll(Collection<?> c); //移除所有在c集合中存在的元素void clear(); //清空集合boolean equals(Object o); //是否相等int hashCode(); //计算hashcodedefault Spliterator<E> spliterator() {} //获取可分割迭代器
主要的子类:
队列接口,在Collection接口的接触上添加了增删改查接口定义,一般默认是先进先出,即FIFO,除了优先队列和栈,优先队列是自己定义了排序的优先顺序,队列中不允许放入null元素。
下面是源码:
boolean add(E e); //插入一个元素到队列,失败时返回IllegalStateException (如果队列容量不够)boolean offer(E e); //插入一个元素到队列,失败时返回falseE remove(); //移除队列头的元素并移除E poll(); //返回并移除队列的头部元素,队列为空时返回nullE element(); //返回队列头元素E peek(); //返回队列头部的元素,队列为空时返回null
主要的子接口以及实现类有:
对于Collection集合我们应该使用哪一个?
每个实现都有自己的特点,重要的是知道当前数据以及业务的特点,选取最适合的集合类进行数据操作。
Collection
接口是存储单列元素,而Map
是键值对Collection
接口继承了Iterable
接口,而Map
则不是,Map
是在各自的实现类中才用内部类的方式实现Iterator
接口,例如HashMap
,key或者value或者它们的组合entry都可以使用迭代器进行遍历。HashSet
的底层实现其实就是定义了一个HashMap
,TreeSet
同样依赖于Map接口的子实现类TreeMap
。Map
集合可以存储键值对,可以获取所有的键,或者值或者键值对,键不允许重复,但是值可以重复。
随便说说Map
相关的子类:
(1).Collection
是集合的顶级接口之一,衍生出了Set
,List
,Queue
等一系列接口以及实现类。而Collections
是一个辅助类,就是实现一些排序,搜索,线程安全等功能,它主要体现的功能是操作集合,而Collection
则是集合本身。
(2).Collection
是接口,其本身不能实例化,但是可以实例化为其子类或者实现类,但是Collections
是包装类,一般不会实例化,直接调用static方法。
Collections
接口主要提供了以下操作,只展示了部分,详细需要后面文章说:
public static<T extends Comparable
,元素需要实现Comparable
接口,按照比较器进行排序。public static
,public static void reverse(List
反转顺序public static void shuffle(List
,将list的元素随机打乱。public static void swap(List
交换两个索引的元素public static
,copy出一个内容一致的list
。static<T extends Object & Comparable
static<T extends Object & Comparable
public static void rotate(List
public static
public static int lastIndexOfSubList(List
Collection
接口继承了iterable
接口,是集合的顶级接口之一,衍生接口有List
,Set
,Queue
等,主要定义了元素的基本操作,删除,添加等等方法,迭代一个Collection
可以使用Iterator
,但是Collection
本身不能实例化。
ps:几个文章有许多重叠之处,但是不写又感觉说不清,或许拓展和收口对写一篇文章都极其重要,有些知识同样需要不断重复,拓展,才能形成整个知识结构。当是自己的学习笔记以及总结,如果有错误或者遗漏之处,感谢指出~
此文章仅代表自己(本菜鸟)学习积累记录,或者学习笔记,如有侵权,请联系作者删除。人无完人,文章也一样,文笔稚嫩,在下不才,勿喷,如果有错误之处,还望指出,感激不尽~
技术之路不在一时,山高水长,纵使缓慢,驰而不息。
公众号:秦怀杂货店