注:本文只能在JDK1.8以前进行参考,JDK1.8对作了速度的优化,好比HashMap采用了红黑树,JVM内存划分也发生了改变java
本文大部份内容转载自List接口、Set接口和Map接口,本身在阅读的时候作了一些补充数组
1、集合与数组安全
数组(能够存储基本数据类型)是用来存现对象的一种容器,可是数组的长度固定,不适合在对象数量未知的状况下使用。数据结构
集合(只能存储对象-基本数据类型使用它的包装类(固然若是在添加的时候你也可使用list.add(1),由于Java会对基本数据类型作自动包装),对象类型能够不同)的长度可变,可在多数状况下使用。并发
2、层次关系异步
如图所示:图中,实线边框的是实现类,折线边框的是抽象类,而点线边框的是接口性能
Collection接口是集合类的根接口,Java中没有提供这个接口的直接的实现类。可是却让其被继承产生了两个接口,就是Set和List。Set中不能包含重复的元素。List是一个有序的集合,能够包含重复的元素,提供了按索引访问的方式。测试
Map是Java.util包中的另外一个接口,它和Collection接口没有关系,是相互独立的,可是都属于集合类的一部分。Map包含了key-value对。Map不能包含重复的key,可是能够包含相同的value。优化
看到这里是否是发现Set和Map具备相同的功能“元素不能重复”,根本缘由就是Set的底层都是用对应的Map。好比:HashSet底层就是一个HashMapthis
Iterator,全部的集合类,都实现了Iterator接口,这是一个用于遍历集合中元素的接口,主要包含如下三种方法:
1.hasNext()是否还有下一个元素。
2.next()返回下一个元素。
3.remove()删除当前元素。
补充:JDK1.8为了提供数据源遍历的速度,提供了Spliterator,好比ArrayList的部分源代码:
public Spliterator<E> spliterator() { return new ArrayListSpliterator<>(this, 0, -1, 0); }
3、几种重要的接口和类简介
一、List(有序、可重复)
List里存放的对象是有序的,同时也是能够重复的,List关注的是索引,拥有一系列和索引相关的方法,查询速度快。由于往list集合里插入或删除数据时,会伴随着后面数据的移动,全部插入删除数据速度慢。
二、Set(无序、不能重复)
Set里存放的对象是无序,不能重复的,集合中的对象不按特定的方式排序,只是简单地把对象加入集合中。
三、Map(键值对、键惟1、值不惟一)
Map集合中存储的是键值对,键不能重复,值能够重复。根据键获得值,对map集合遍历时先获得键的set集合,对set集合进行遍历,获得相应的值。
对好比下:
|
|
是否有序 |
是否容许元素重复 |
Collection |
|
|
|
List |
是 |
是 |
|
Set |
AbstractSet |
否 |
否 |
|
HashSet |
||
|
TreeSet |
是(用二叉排序树) |
|
Map |
AbstractMap |
否 |
使用key-value来映射和存储数据,key必须惟一,value能够重复 |
|
HashMap |
||
|
TreeMap |
是(用二叉排序树) |
4、遍历
在类集中提供了如下四种的常见输出方式:
1)Iterator:迭代输出,是使用最多的输出方式。
2)ListIterator:是Iterator的子接口,专门用于输出List中的内容。
3)foreach输出:JDK1.5以后提供的新功能,能够输出数组或集合。
4)for循环
代码示例以下:
for的形式:for(int i=0;i<arr.size();i++){...}
foreach的形式: for(int i:arr){...}
iterator的形式:
Iterator it = arr.iterator();
while(it.hasNext()){ object o =it.next(); ...}
4)在JDK1.8新增了并行遍历:
-----待补充
5、ArrayList和LinkedList
ArrayList和LinkedList在用法上没有区别,可是在功能上仍是有区别的。LinkedList常常用在增删操做较多而查询操做不多的状况下,ArrayList则相反,为何喃?????
ArrayList底层就是一个数组,数组是一块连续的内存空间,支持下标访问,因此查询很快,若是要更新设计到数据的复制,因此它适用于查询
LinkedList底层是一个LinkedList.Node链表(关于链表的结构能够度娘一下),内存是分散的,不支持下标访问,可是链表更新就很快,只须要改变引用的地址就能够,因此它适用于更新
6、Map集合
实现类:HashMap、Hashtable、LinkedHashMap和TreeMap
HashMap
HashMap是最经常使用的Map,它根据键的HashCode值存储数据,根据键能够直接获取它的值,具备很快的访问速度,遍历时,取得数据的顺序是彻底随机的。由于键对象不能够重复,因此HashMap最多只容许一条记录的键为Null,容许多条记录的值为Null,是非同步的
HashMap底层是一个Entry数组,而Entry是支持单向链表的,因此它就是一个链表数组,同一个Key计算出来的HashCode值若是同样,就会在链表头插入新的Entry。当从HashMap中获取值时,若是HashCode值同样,再使用equals方法判断Key是否是同一个,是则返回,不然返回Null。
注:这是JDK1.8以前的版本,JDK1.8不同了,在链表尾添加新的Entry,若是链表长度超过8,则会转换为红黑树,get()的效率更高
有兴趣的同窗能够看看HashMap的源代码
添加部分:
void addEntry(int hash, K key, V value, int bucketIndex) { //若是Map中元素大于阈值就扩充Map的容量 if ((size >= threshold) && (null != table[bucketIndex])) { resize(2 * table.length); hash = (null != key) ? hash(key) : 0; bucketIndex = indexFor(hash, table.length); } //建立新的Entry,以前存在的Entry放在新的后面 createEntry(hash, key, value, bucketIndex); }
获取部分:
final Entry<K,V> getEntry(Object key) { if (size == 0) { return null; } int hash = (key == null) ? 0 : hash(key); //根据hash值找到对应的链表,遍历链表,若是hash值相等而且对象相等就认为找到了真正的Key,返回Value for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } return null; }
Hashtable
Hashtable与HashMap相似,是HashMap的线程安全版,它支持线程的同步,即任一时刻只有一个线程能写Hashtable,所以也致使了Hashtale在写入时会比较慢,它继承自Dictionary类,不一样的是它不容许记录的键或者值为null,同时效率较低。
ConcurrentHashMap
线程安全,而且锁分离。ConcurrentHashMap内部使用段(Segment)来表示这些不一样的部分,每一个段其实就是一个小的hash table,它们有本身的锁。只要多个修改操做发生在不一样的段上,它们就能够并发进行。
LinkedHashMap
LinkedHashMap保存了记录的插入顺序,在用Iteraor遍历LinkedHashMap时,先获得的记录确定是先插入的,在遍历的时候会比HashMap慢,有HashMap的所有特性。
更详细的介绍看:Java LinkedHashMap工做原理及实现
TreeMap
TreeMap实现SortedMap接口,可以把它保存的记录根据键排序,默认是按键值的升序排序(天然顺序),也能够指定排序的比较器,当用Iterator遍历TreeMap时,获得的记录是排过序的。不容许key值为空,非同步的;
底层是一个平衡二叉树,这个东西我本身目前也还不熟悉,后面买本数据结构的书看看再写。
map的遍历
第一种:KeySet()
将Map中全部的键存入到set集合中。由于set具有迭代器。全部能够迭代方式取出全部的键,再根据get方法。获取每个键对应的值。 keySet():迭代后只能经过get()取key 。
取到的结果会乱序,是由于取得数据行主键的时候,使用了HashMap.keySet()方法,而这个方法返回的Set结果,里面的数据是乱序排放的。
典型用法以下:
Map map = new HashMap();
map.put("key1","lisi1");
map.put("key2","lisi2");
map.put("key3","lisi3");
map.put("key4","lisi4");
//先获取map集合的全部键的set集合,keyset()
Iterator it = map.keySet().iterator();
//获取迭代器
while(it.hasNext()){
Object key = it.next();
System.out.println(map.get(key));
}
第二种:entrySet()
Set<Map.Entry<K,V>> entrySet() //返回此映射中包含的映射关系的 Set 视图。(一个关系就是一个键-值对),就是把(key-value)做为一个总体一对一对地存放到Set集合当中的。Map.Entry表示映射关系。entrySet():迭代后能够e.getKey(),e.getValue()两种方法来取key和value。返回的是Entry接口。
典型用法以下:
Map map = new HashMap();
map.put("key1","lisi1");
map.put("key2","lisi2");
map.put("key3","lisi3");
map.put("key4","lisi4");
//将map集合中的映射关系取出,存入到set集合
Iterator it = map.entrySet().iterator();
while(it.hasNext()){
Entry e =(Entry) it.next();
System.out.println("键"+e.getKey () + "的值为" + e.getValue());
}
推荐使用第二种方式,即entrySet()方法,效率较高。
对于keySet实际上是遍历了2次,一次是转为iterator,一次就是从HashMap中取出key所对于的value。而entryset只是遍历了第一次,它把key和value都放到了entry中,因此快了。两种遍历的遍历时间相差仍是很明显的。
7、主要实现类区别小结
Vector和ArrayList
1,vector是线程同步的,因此它也是线程安全的,而arraylist是线程异步的,是不安全的。若是不考虑到线程的安全因素,通常用arraylist效率比较高。
2,若是集合中的元素的数目大于目前集合数组的长度时,vector增加率为目前数组长度的100%,而arraylist增加率为目前数组长度的50%。若是在集合中使用数据量比较大的数据,用vector有必定的优点。
3,若是查找一个指定位置的数据,vector和arraylist使用的时间是相同的,若是频繁的访问数据,这个时候使用vector和arraylist均可以。而若是移动一个指定位置会致使后面的元素都发生移动,这个时候就应该考虑到使用linklist,由于它移动一个指定位置的数据时其它元素不移动。
ArrayList 和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增长和插入元素,都容许直接序号索引元素,可是插入数据要涉及到数组元素移动等内存操做,因此索引数据快,插入数据慢,Vector因为使用了synchronized方法(线程安全)因此性能上比ArrayList要差,LinkedList使用双向链表实现存储,按序号索引数据须要进行向前或向后遍历,可是插入数据时只须要记录本项的先后项便可,因此插入数度较快。
arraylist和linkedlist
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.对于随机访问get和set,ArrayList以为优于LinkedList,由于LinkedList要移动指针。
3.对于新增和删除操做add和remove,LinedList比较占优点,由于ArrayList要移动数据。 这一点要看实际状况的。若只对单条数据插入或删除,ArrayList的速度反而优于LinkedList。但如果批量随机的插入删除数据,LinkedList的速度大大优于ArrayList. 由于ArrayList每插入一条数据,要移动插入点及以后的全部数据。
HashMap与TreeMap
一、 HashMap经过hashcode对其内容进行快速查找,而TreeMap中全部的元素都保持着某种固定的顺序,若是你须要获得一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。
二、在Map 中插入、删除和定位元素,HashMap是最好的选择。但若是您要按天然顺序或自定义顺序遍历键,那么TreeMap会更好。使用HashMap要求添加的键类明肯定义了hashCode()和 equals()的实现。
两个map中的元素同样,但顺序不同,致使hashCode()不同。
一样作测试:
在HashMap中,一样的值的map,顺序不一样,equals时,false;
而在treeMap中,一样的值的map,顺序不一样,equals时,true,说明,treeMap在equals()时是整理了顺序了的。
HashTable与HashMap 一、同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的。 二、HashMap容许存在一个为null的key,多个为null的value 。 三、hashtable的key和value都不容许为null