java的集合框架详细解读(基于jdk1.8)
java集合框架
java集合框架需要掌握的是六大接口(Collection、Set、List、Map、Iterator和Comparable)和两个工具类Arrays和Collections。
Collection接口继承了Iterable接口,是最基本集合接口,由于Iterable接口依赖Iterator接口,所以所有实现Collection接口的容器类都有iterator方法,用于返回一个实现了Iterator接口的对象。Iterator对象称作迭代器,Iterator接口方法能以迭代方式逐个访问集合中各个元素,并可以从Collection中除去适当的元素。另外由Collection接口派生出3个主要接口,分别是List ,Set,Queue。
Map也是接口,但没有继承Collection接口。该接口描述了从不重复的键到值的映射。Map接口用于维护键/值对(key/value pairs)。
Comparable可以用于比较的实现,实现了Comparable接口的类可以通过实现comparaTo方法从而确定该类对象的排序方式。
另外就是两个重要的工具类,分别是用来操作数组、集合的Arrays和Collections,例如在ArrayList和Vector中大量调用了Arrays.Copyof()方法,而Collections中有很多静态方法可以返回各集合类的synchronized版本,即线程安全的版本,当然了,如果要用线程安全的结合类,首选Concurrent并发包下的对应的集合类。
Collection接口概览
Collection接口
|
|
在Java8的新特性中有一个新特性为接口默认方法,该新特性允许我们在接口中添加一个非抽象的方法实现,而这样做的方法只需要使用关键字default修饰该默认实现方法即可。该特性又叫扩展方法。
List接口概览
List是一个继承Collection接口的接口,当然间接的继承了Iterable接口,实现类包括:ArrayList、LinkedList、Vector等。List是有序的Collection可以对每个元素的插入位置进行精准控制,可以根据索引访问元素,允许重复元素,有自己的迭代器 ListIterator。Java8有28个方法,我们只列举常见方法,也是后面会主要分析其实现的方法。
|
|
ArrayList
ArrayList是一个可改变大小的数组,当更多的元素加入到ArrayList中时,其大小将会动态的增长。内部的元素可以直接通过get与set方法进行访问,因为ArrayList本质上就是一个数组。ArrayList不是线程安全的,只能在单线程环境下,多线程环境下可以考虑用 collections.synchronizedList(List l)函数返回一个线程安全的ArrayList类,也可以使用concurrent并发包下的CopyOnWriteArrayList类。ArrayList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问,实现了Cloneable接口,能被克隆。
初始化代码
|
|
涉及知识点:
transient
|
|
三种构建方法
第一个构造方法使用提供的initialCapacity来初始化elementData数组的大小。
第二个构造方法调用第一个构造方法并传入参数10,即默认elementData数组的大小为10。
第三个构造方法则将提供的集合转成数组返回给elementData(返回若不是Object[]将调用Arrays.copyOf方法将其转为Object[])。
|
|
add方法代码
boolean add(E e)
void add(int index, E element)
boolean addAll(Collection<? extends E> c)
boolean addAll(int index,Collection<? extends E> c)
|
|
remove方法代码
E remove(int index)
boolean remove(Object o)
void removeRange(int fromIndex, int toIndex)
|
|
get方法代码
E get(int index)
E set(int index, E element)
|
|
clear方法代码
|
|
clone方法代码
调用父类的clone方法返回一个对象的副本,将返回对象的elementData数组的内容赋值为原对象elementData数组的内容,将副本的modCount设置为0。
|
|
indexOf(Object o)方法代码
|
|
lastIndexOf(Object o)方法代码
|
|
writeObject和readObject方法代码
void writeObject(java.io.ObjectOutputStream s)
void readObject(java.io.ObjectInputStream s)
|
|
其他方法
boolean contains(Object o)
boolean isEmpty()
int size()
Object[] toArray()
T[] toArray(T[] a)
void trimToSize()
|
|
几点说明:
ArrayList的实现中大量地调用了Arrays.copyof()和System.arraycopy()方法
Arrays.copyof()方法
|
|
System.arraycopy()方法
该方法被标记了native,调用了系统的C/C++代码,在JDK中是看不到的,但在openJDK中可以看到其源码。该函数实际上最终调用了C语言的memmove()函数,因此它可以保证同一个数组内元素的正确复制和移动,比一般的复制方法的实现效率要高很多,很适合用来批量处理数组。Java强烈推荐在复制大量数组元素时用该方法,以取得更高的效率。
LinkedList
LinkedList 是一个双向循环链表,在添加和删除元素时具有比ArrayList更好的性能。但在get与set方面弱于ArrayList。当然这些对比都是指数据量很大或者操作很频繁的情况下的对比,如果数据和运算量很小,那么对比将失去意义。 LinkedList还实现了Queue接口,该接口比List提供了更多的方法,包括offer(),peek(),poll()等。所以除了可以当作链表来操作外,它还可以当作栈,队列和双端队列来使用。LinkedList同样是非线程安全的,只在单线程下适合使用。LinkedList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,实现了Cloneable接口,能被克隆。
初始化代码
|
|
两种构建方法
无参构造方法和Collection的构造方法,先调用无参构造方法建立一个空链表,然后将Collection中的数据加入到链表的尾部后面。
|
|
add方法代码
boolean add(E e)
void add(int index, E element)
void addFirst(E e)
void addLast(E e)
void push(E e)
boolean offer(E e)
boolean offerLast(E e)
boolean offerFirst(E e)
E set( int index, E element)
boolean addAll(Collection<? extends E> c)
boolean addAll(int index, Collection<? extends E> c)
|
|
get方法代码
E get(int index)
E getFirst()
E getLast()
E peekFirst()
E peekLast()
E peek()
E element()
|
|
remove方法代码
E poll()
E removeFirst()
E removeLast()
E pollFirst()
E pollLast()
E pop()
boolean removeLastOccurrence(Object o)
boolean removeLastOccurrence(Object o)
|
|
clear方法代码
|
|
lastIndexOf(Object o)方法代码
|
|
listIterator(int index)方法代码
|
|
其他方法
boolean contains(Object o)
int size()
|
|
Vector
Vector 和ArrayList类似,但属于强同步类。如果你的程序本身是线程安全的(thread-safe,没有在多个线程之间共享同一个集合/对象),那么使用ArrayList是更好的选择。 Vector和ArrayList在更多元素添加进来时会请求更大的空间。Vector每次请求其大小的双倍空间,而ArrayList每次对size增长50%。
Vector的API源码显的比较臃肿、基本现在已经不再推荐使用Vector了、可以使用经过处理后的ArrayList来代替多线程环境中的Vector。
初始化代码
Vector是JDK1.0引入了,它的很多实现方法都加入了同步语句,因此是线程安全的,可以用于多线程环境。
Vector实现了Serializable接口,因此它支持序列化,同时实现了Cloneable接口,能被克隆,实现了RandomAccess接口,支持快速随机访问。
Vector继承了AbstractList,实现了List,它是一个队列,因此实现了相应的添加、删除、修改、遍历等功能。
源码基于jdk1.8
|
|
四种构建方法
|
|
add方法代码
synchronized boolean add(E e)
void add(int index, E element)
synchronized boolean addAll(Collection<? extends E> c)
synchronized boolean addAll(int index, Collection<? extends E> c)
synchronized void addElement(E obj)
synchronized E set(int index, E element)
synchronized void insertElementAt(E obj, int index)
|
|
get方法代码
synchronized E get(int index)
synchronized E elementAt(int index)
|
|
remove方法代码
boolean remove(Object o)
synchronized E remove(int index)
synchronized boolean removeElement(Object obj)
synchronized void removeElementAt(int index)
synchronized void removeAllElements()
boolean removeAll(Collection<?> c)
|
|
clear方法代码
void clear()
|
|
indexOf方法
int indexOf(Object o)
synchronized int indexOf(Object o, int index)
|
|
lastIndexOf方法代码
synchronized int lastIndexOf(Object o)
synchronized int lastIndexOf(Object o, int index)
|
|
clone方法代码
|
|
hashcode方法代码
|
|
equals方法代码
|
|
listIterator(int index)方法代码
synchronized ListIterator
synchronized ListIterator
|
|
synchronized Iterator
|
|
其他方法
synchronized int capacity()
boolean contains(Object object)
synchronized boolean containsAll(Collection<?> collection)
synchronized void copyInto(Object[] elements)
Enumeration
synchronized void ensureCapacity(int minimumCapacity)
synchronized E firstElement()
synchronized boolean isEmpty()
synchronized E lastElement()
synchronized boolean retainAll(Collection<?> collection)
synchronized void setSize(int length)
synchronized int size()
synchronized List
synchronized
synchronized Object[] toArray()
synchronized String toString()
synchronized void trimToSize()
|
|
Stack
Stack(栈)是以栈的形式来存储数据,其特点是先进后出(FILO),同时Stack继承与Vector,所以如果把Stack内部的实现也是通过动态数组来实现的、而不是其他的数据结构。在List体系中有个LinkedList是以双向链表的数据结构来存储数据的,使用LinkedList完全可以达到Stack的效果、但是Stack不能作为双向链表来使用,并且LinkedList不是线程安全的、而Stack是线程安全的。
|
|
Queue接口概览
是一个泛型接口,父接口:Collection,子接口:Deque。
|
|
boolean add(E e)和 boolean offer(E e)调用相同。
E element()和E peek()获取但不移除失败时,element抛出异常,peek()返回null
E remove()和E poll()获取并移除失败时,remove()抛出异常,poll()返回null
Deque 双端队列,可以实现队列,也可以用作栈。
Set接口概览
存入Set的每个元素必须是惟一的,因为Set不保存重复元素。加入Set的元素重新必须定义equals()方法和hashcode()方法以确保对象的唯一性。Set不保证维护元素的次序,Set与Collection有完全一样的接口。
HashSet
初始化代码
HashSet继承了AbstractSet,实现了Set接口。其实AbstractSet已经实现Set接口了。AbstractSet继承自AbstractCollection,而AbstractCollection实现了Collection接口的部分方法,而Set接口和Collection接口完全一致,所以AbstractSet只是实现了AbstractCollection没有实现的Set接口的方法和重写了部分AbstractCollection已经实现的方法。对于HashSet中保存的对象,请注意正确重写其equals和hashCode方法,以保证放入的对象的唯一性。
|
|
五种构建方法
|
|
add方法代码
boolean add(E e)
|
|
get方法代码
通过Iterator遍历HashSet
|
|
|
|
remove方法代码
|
|
clear方法代码
|
|
clone()方法代码
|
|
writeObject和readObject方法代码
void writeObject(java.io.ObjectOutputStream s)
void readObject(java.io.ObjectInputStream s)
|
|
其他方法
size()方法
|
|
isEmpty()方法
|
|
contains(Object)方法
|
|
LinkedHashSet
LinkedHashSet会调用HashSet的父类构造函数,让其底层实现为LinkedHashMap,这样就很好的实现了LinkedHashSet所需要的功能。
初始化代码
|
|
四种构建方法
|
|
TreeSet
TreeSet底层实现严重依赖于TreeMap。
未完待续
Collections与Arrays工具类
Collection是一个接口,它是Set、List等容器的父接口;Collections是一个工具类,提供了一系列的静态方法来辅助容器操作,这些方法包括对容器的搜索、排序、线程安全化等等。
Collections的常用方法
sort排序
|
|
由此可以看出我们有两种方式排序,list中的对象实现Comparable接口以及根据Collections.sort重载方法来实现。
list中的对象实现Comparable接口
|
|
|
|
根据Collections.sort重载方法来实现
|
|
|
|
shuffle 随机排序
|
|
binarySearch
查找指定集合中的元素,返回所查找元素的索引
|
|
max
|
|
min
|
|
indexOfSubList
查找subList在list中首次出现位置的索引
|
|
lastIndexOfSubList
同上
replaceAll
替换批定元素为某元素,若要替换的值存在刚返回true,反之返回false
|
|
reverse
反转集合中元素的顺序
|
|
rotate
集合中的元素向后移m个位置,在后面被遮盖的元素循环到前面来
|
|
copy
将集合n中的元素全部复制到m中,并且覆盖相应索引的元素
|
|
swap
交换集合中指定元素索引的位置
|
|
fill
|
|
nCopies
返回大小为n的List,List不可改变,其中的所有引用都指向o
|
|
Arrays常用方法
asList方法
|
|
binarySearch方法
binarySearch方法支持在整个数组中查找
|
|
在某个区间范围内查找
|
|
copyOf及copyOfRange方法
sort方法
toString方法
deepToString方法
|
|
equals方法
deepEquals方法
|
|
fill方法
|
|
Map接口概览
Map一次存一对元素, Collection 一次存一个。Map 的键不能重复,保证唯一。Map 一次存入一对元素,是以键值对的形式存在。键与值存在映射关系,一定要保证键的唯一性。
Map接口常用方法
1、添加:
|
|
2、删除
|
|
3、获取
|
|
3、判断:
|
|
4、长度:
|
|
5、遍历Map的方式:
|
|
HashMap
Java8的HashMap对之前做了较大的优化,其中最重要的一个优化就是桶中的元素不再唯一按照链表组合,也可以使用红黑树进行存储,总之,目标只有一个,那就是在安全和功能性完备的情况下让其速度更快,提升性能。
初始化代码
|
|
四种构建方法
HashMap(int, float)
HashMap(int)
HashMap()
HashMap(Map<? extends K>)
|
|
put方法代码
|
|
get方法代码
|
|
remove方法代码
|
|
clear方法代码
|
|
clone方法代码
|
|
其他方法
略
LinkedHashMap
我们需要按照元素插入的顺序来访问元素,此时,LinkedHashMap就派上用场了。LinkedHashMap是HashMap的直接子类,二者唯一的区别是LinkedHashMap在HashMap的基础上,采用双向链表(doubly-linked list)的形式将所有entry连接起来,这样是为保证元素的迭代顺序跟插入顺序相同。除了可以保迭代历顺序,这种结构还有一个好处:迭代LinkedHashMap时不需要像HashMap那样遍历整个table,而只需要直接遍历header指向的双向链表即可,也就是说LinkedHashMap的迭代时间就只跟entry的个数相关,而跟table的大小无关。
初始化代码
|
|
五种构建方法
LinkedHashMap(int, float)
LinkedHashMap(int)
LinkedHashMap()
LinkedHashMap(Map<? extends K, ? extends V>)
LinkedHashMap(int, float, boolean)
|
|
未完待续
HashTable
初始化代码
|
|
四种构建方法
|
|
put方法代码
|
|
get方法代码
|
|
remove方法代码
|
|
clear方法代码
|
|
clone方法代码
|
|
TreeMap
TreeMap底层使用的数据结构是红黑树,HashMap在达到一定阈值时候会使用红黑树。
未完待续
Iterator接口概览
Iterator接口也是Java集合框架的成员,主要用于遍历(即迭代访问)Collection集合中的元素,Iterator对象也被称为迭代器。
|
|
Comparable接口概览
在Java集合框架里面,各种集合的操作很大程度上都离不开Comparable和Comparator,虽然它们与集合没有显示的关系,但是它们只有在集合里面的时候才能发挥最大的威力。
Comparable
|
|
Comparator
|
|
示例:
|
|
|
|