集合框架图
Java集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射。Collection接口又有3种子类型,List、Set和Queue,再下面是一些抽象类,最后是具体实现类,常用的有ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap等等。
Collection接口
Collection接口是处理对象集合的根接口,其中定义了很多对元素进行操作的方法,AbstractCollection是提供Collection部分实现的抽象类。
Collection接口里面定义的方法
- size(): int
- isEmpty: boolean
- contains(Object): bollean
- iterator(): Iterator<E>
- toArray(): Object[]
- toArray(T[])<T>: T[]
- add(E): boolean
- remove(Object) : boolean
- containsAll(Collection<?> ): boolean
- removeAll(Collection<?>): boolean
- removeIf(Predicate<? super E >): boolean
- retainAll(Collection<?>):boolean
- clear(): void
- equals(Object) : boolean
- hashCCode(): int
- spliterator(): Spliterator<E>
- stream(): Stream<E>
- parallelStream(): Steam<E>
List接口
List可以定义一个允许重复的有序集合,List接口主要是增加了面向位置的操作,允许在指定位置上操作元素,同时增加了一个能够双向遍历线性表的新列表迭代器ListIterator。AbstractList类提供了List接口的部分实现,AbstractSequentialList扩展自AbstractList,主要是提供对链表的支持。可能最常用的类,ArrayList和LinkedList
ArrayList
用动态数组存储元素,这个数组可以动态创建,如果元素个数超过了数组的容量,那么就创建一个更大的新数组,并将当前数组中的所有元素都复制到新数组中。LinkedList
LinkedList是在一个链表中存储元素。ArrayList与LinkedList的差异
若只对单条数据插入或删除,ArrayList的速度反而优于LinkedList。但若是批量随机的插入删除数据,LinkedList的速度大大优于ArrayList. 因为ArrayList每插入一条数据,要移动插入点及之后的所有数据。
对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。查找操作indexOf,lastIndexOf,contains等,两者差不多。
ArrayList线程不安全,查询块,因为是数组来构成的。
Set接口
Set接口扩展自Collection,它与List的不同之处在于,规定Set的实例不包含重复的元素。在一个规则集内,一定不存在两个相等的元素。AbstractSet是一个实现Set接口的抽象类,Set接口有三个具体实现类,分别是散列集HashSet、链式散列集LinkedHashSet和树形集TreeSet。
HashSet散列集
散列集HashSet是一个用于实现Set接口的具体类,可以使用它的无参构造方法来创建空的散列集,也可以由一个现有的集合创建散列集。在散列集中,有两个名词需要关注,初始容量和客座率。客座率是确定在增加规则集之前,该规则集的饱满程度,当元素个数超过了容量与客座率的乘积时,容量就会自动翻倍。输出的时候是无序的,跟add()添加元素的顺序无关。LinkedHashSet链式散列集
LinkedHashSet是用一个链表实现来扩展HashSet类,它支持对规则集内的元素排序。HashSet中的元素是没有被排序的,而LinkedHashSet中的元素可以按照它们插入规则集的顺序提取。TreeSet树形集
TreeSet扩展自AbstractSet,并实现了NavigableSet,AbstractSet扩展自AbstractCollection,树形集是一个有序的Set,其底层是一颗树,这样就能从Set里面提取一个有序序列了。在实例化TreeSet时,我们可以给TreeSet指定一个比较器Comparator来指定树形集中的元素顺序。
Queue接口
队列是一种先进先出的数据结构,元素在队列末尾添加,在队列头部删除。Queue接口扩展自Collection,并提供插入、提取、检验等操作。
Queue接口方法
- add(E):
增加一个元索,如果队列已满,则抛出一个IIIegaISlabEepeplian异常 - offer(E):bolean
添加一个元素并返回true,如果队列已满,则返回false - poll(): E
移除并返问队列头部的元素,如果队列为空,则返回null - remove(): E
移除并返回队列头部的元素,如果队列为空,则抛出一个NoSuchElementException异常 - peek(): E
返回队列头部的元素,如果队列为空,则返回null - element(): E
返回队列头部的元素,如果队列为空,则抛出一个NoSuchElementException异常
接口Deque,是一个扩展自Queue的双端队列,它支持在两端插入和删除元素,因为LinkedList类实现了Deque接口,所以通常我们可以使用LinkedList来创建一个队列。PriorityQueue类实现了一个优先队列,优先队列中元素被赋予优先级,拥有高优先级的先被删除。
Map接口
Map是一种存储键值对映射的容器类,在Map中键可以
任意类型的对象,但不能有重复的键,每个键都对应一个值,真正存储在图中的是键值构成的条目。
- Map存储元素使用put方法,Collection使用add方法
- Map集合没有直接取出元素的方法,而是先转成Set集合,在通过迭代获取元素
- Map集合中键要保证唯一性
HashMap
HashMap是基于哈希表的Map接口的非同步实现,继承自AbstractMap,AbstractMap是部分实现Map接口的抽象类。JDK1.8中,HashMap采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
HashMap:线程不安全,速度快,允许存放null键。
关于HashMap与HashTable
相同:他们都是集合类,用来存放java对象。
区别:
- 历史原因
Hashtable是基于陈旧的Dictionary类的,HashMap是jdk1.2之后引入的一个基于Map接口的一个实现。 - 同步性
Hashtable是线程同步的,而HashMap不是,他是异步的。因而Hashtable是线程安全的,HashMap非线程安全。当然因为线程安全,所以执行效率低,HashMap非线程安全则执行效率高,速度快。(如:多个线程去同时请求一个程序(如服务器),则如果是线程安全则会用到锁的概念,在程序响应一个线程的时候会将该程序锁定,让其他过来响应的线程等待,并且是按序等待,所以他是安全的,不会造成程序崩溃)。如果不用到线程安全,则应该首选HaspMap,这样运行效率会高一些。 - 值
HaspMap可以将空值null作为key或者value。但Hashtable是不能的。 - 方法
HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey;因为contains方法容易让人引起误解。
LinkedMap
LinkedHashMap继承自HashMap,它主要是用链表实现来扩展HashMap类,HashMap中条目是没有顺序的,但是在LinkedHashMap中元素既可以按照它们插入图的顺序排序,也可以按它们最后一次被访问的顺序排序。
TreeMap
TreeMap基于红黑树数据结构的实现,键值可以使用Comparable或Comparator接口来排序。TreeMap继承自AbstractMap,同时实现了接口NavigableMap,而接口NavigableMap则继承自SortedMap。SortedMap是Map的子接口,使用它可以确保图中的条目是排好序的。
在实际使用中,如果更新图时不需要保持图中元素的顺序,就使用HashMap,如果需要保持图中元素的插入顺序或者访问顺序,就使用LinkedHashMap,如果需要使图按照键值排序,就使用TreeMap。
Iterator迭代器
迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。并且只能单向移动
迭代器可用与Collection框架内的所有类型的集合,由图可以看出Collection是继承了Iterator的。
- 为什么要用迭代器
一方面,迭代器的开销开销比较小,在访问集合对象时候能节省内存
另一方面,通过for循环来访问集合对象的时候,不能对集合对象进行删操作,而迭代器可以。
Iterarot与ListIterator不同
- 使用范围不同,Iterator可以应用于所有的集合,Set、List和Map和这些集合的子类型。而ListIterator只能用于List及其子类型。
- ListIterator有add方法,可以向List中添加对象,而Iterator不能。
- ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator不可以。
- ListIterator可以定位当前索引的位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。
- 都可实现删除操作,但是ListIterator可以实现对象的修改,set()方法可以实现。Iterator仅能遍历,不能修改。