Map的key是一个Set,可是Map的value不是一个List,不过能够将其看作一个List。java
Map的values()方法返回的是map的全部value,可是它不是一个List,而是一个内部类Values数组
HashMap中的特性安全
查看values源代码:性能
public Collection<V> values() { Collection<V> vs = values; return (vs != null ? vs : (values = new Values())); }
能够看出,values方法返回的是一个集合:newValues()~!this
该内部类以下:spa
private final class Values extends AbstractCollection<V> { public Iterator<V> iterator() { //返回newValueIterator方法的返回值 return newValueIterator(); } public int size() { //返回外部类实例的size实例变量的返回值 return size; } public boolean contains(Object o) { //返回外部类实例的containsValue(o)的返回值 return containsValue(o); } public void clear() { //调用外部类实例的clear方法 HashMap.this.clear(); } }
这个Values类继承AbstractCollection,可是它却不算一个集合类,由于它没有add方法,即不能够添加元素,不能存储任何java对象。它的做用是遍历Map中全部的value线程
遍历方法iterator():主要是依赖ValueIterator类:code
查看newValueIterator类:对象
查看nextEntry方法:继承
在TreeMap中方法是相似的,可是因为它是经过红黑树实现的,因此它遍历的时候仍是利用的二叉树的特色:查找子节点。。。。再也不叙述
综上:
Map的values方法返回的是map的全部value,该value是一个不能存储元素的Collection的实现类,因此程序遍历该集合便是遍历map的全部value
Map和List的实现没有太大的类似之处,就是用法挺像
List主要有三个实现类:ArrayList,Vector,LinkedList
Vector有一个实现类:Stack,它只比Vector多了5个方法,本质上仍是一个Vector,它们是线程安全的,不过已经再也不推荐使用了,从1.6版本开始,已经被Deque取代,它也有一个实现类ArrayDeque,它既有队列的性质又有栈的性质
Vector基本已被ArrayList取代,它相比ArrayList,优点是线程安全的,不过,使用ArrayList时,也可使用Collection的静态方法来将其包装成线程安全的,故Vector再也不叙述
在ArrayList中有一行
private transient Object[] elementData;
它是用来保存集合的元素的数组,经过transient修饰,保证了序列化时不会直接序列化该数组,而是经过ArrayList提供的writeObject和readObject方法来实现定制序列化。
ArrayList底层采用数组存储,在数据插入的时候,须要作两件事:
1:保证ArrayList底册封装的数组长度大于集合元素的个数
2:将插入位置以后的全部元素总体向后移动一格
查看源代码:
public E remove(int index) { //若是index大于等于size,抛出异常 RangeCheck(index); modCount++; //保证index处的元素 E oldValue = (E) elementData[index]; //计算总体搬家的元素个数 int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index + 1, elementData, index, numMoved); //释放被删除的元素,让GC回收 elementData[--size] = null; // Let gc do its work return oldValue; }
能够看出,当向ArrayList添加删除元素的时候,都须要对数组进行总体搬家,性能较差,可是查找的时候:
直接经过数组取值,性能和数组几乎同样好
添加时:
public void add(int index, E element) { if (index > size || index < 0) throw new IndexOutOfBoundsException( "Index: "+index+", Size: "+size); //保证ArrayList的底层数组老是能够保存全部元素 ensureCapacity(size+1); // Increments modCount!! /*将elementData数组中index后面的全部元素向后移动一格,这样就能够将index处的位置空出来*/ System.arraycopy(elementData, index, elementData, index + 1, size - index); //将新元素放置在index处 elementData[index] = element; size++; }
这里调用了ensureCapacity,源码以下:
能够看到ArrayList在超过当前容量时,固定的将新容量扩充至原来的1.5倍
LinkedList本质上是一个双向链表,所以它也是使用内部类Entry来保存数据元素:
private static class Entry<E> { //集合的元素 E element; //指向下一链表节点的引用 Entry<E> next; //指向上一链表节点的引用 Entry<E> previous; //构造器 Entry(E element, Entry<E> next, Entry<E> previous) { this.element = element; this.next = next; this.previous = previous; } }
能够看出Entry表明双向链表的一个节点,element是元素自己的值,另外就是链表节点的上/下节点的引用,插入数据时形如:
源码:
主要用到两个方法:
entry(index)和addBefore();
emrty(index)是get(int index)的底层实现,因为底层是链表,因此LinkedList必须一个元素一个元素的遍历,直到找到第index个元素
由此能够看出每次查找元素都须要遍历链表自己,性能较差,不能像ArrayList同样直接拿到index处的元素
同时看看get(int index)的源码,就是对entry方法的简单封装
public E get(int index){ return entry(index).element; }
再看看单纯的插入源码:
若是只是单纯的插入,LinkedList的性能会很到,可是若是在指定位置插入的话,性能也会受影响,由于它涉及到了查找元素,增长了搜索过程。
删除也是同理:
先查找,再删除
具体实现:
private E remove(Entry<E> e) { if (e == header) throw new NoSuchElementException(); //先保存要删除的元素 E result = e.element; e.previous.next = e.next; e.next.previous = e.previous; //将被删除的两个元素的引用都置为空,gc回收 e.next = e.previous = null; e.element = null; size--; modCount++; return result; }
能够看出首先将被删除元素保存起来,再将被删除元素的next赋给它上一节点的next,将其previous赋给它next节点的previous,即将它本身自己从链表中剔除了,再把它自己置为null,最后返回以前保存的被删除元素
整体来看,ArrayList的性能优于LinkedList,除非常常添加元素时,否则优先考虑ArrayList
Iterator是一个迭代器接口,用于统一的迭代各类Collention集合,至于各集合返回的Iterator实现类,程序不关心,迭代的方式由各集合的实现类本身实现。
使用Iterator迭代是不要删除集合中的元素,否则会发生ConcurrentModeficationException