事实上Collection的父接口为 Iterable
目的:简单的了解一下Java常用集合的特性以及内部实现。
参考博客: http://blog.sina.com.cn/s/blog_3fba24680100y2yr.html
常用List集合:
特性:
有顺序的,元素可以重复;
遍历:for,迭代;
排序:Comparable Comparator Collections.sort()
ArrayList:
用数组实现的List;
特点:查询效率高,增删效率低 轻量级 线程不安全;
部分源码分析:
构造:
private transient Object[] elementData; public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; } public ArrayList() { this(10); }
这段源代码表示的是一个ArrayList的内部实现为一个Object数组,重载的两个构造方法,默认长度为10。
增加元素:
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } public boolean addAll(Collection extends E> c) { Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); // Increments modCount System.arraycopy(a, 0, elementData, size, numNew); size += numNew; return numNew != 0; }
添加对象的代码块,size表示数组长度。后一个为添加集合对象的代码块。
删除元素:
public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work return oldValue; }
首先检查下标是否越界,List删除后会自懂向前移动下标向前移动一位又是通过 System.arraycopy(elementData, index+1, elementData, index,numMoved);来实现。
那么ArrayList是怎么实现容量自增的呢?
ensureCapacityInternal(size+numNew)表示数组容量的自增函数,调用下面的函数:
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); }
LinkedList:
底层用双向循环链表实现的List;
特点:查询效率低,增删效率高;
构造:
transient Nodefirst; transient Node last; public LinkedList() { } public LinkedList(Collection extends E> c) { this(); addAll(c); }
对于定义来说没有数组,却有个Node对象来看看静态内部类Node的结构:
private static class Node{ E item; Node next; Node prev; Node(Node prev, E element, Node next) { this.item = element; this.next = next; this.prev = prev; } }
双向链表结构更像是一群牵着手的孩子只知道前后是谁。
添加元素:
void linkLast(E e) { final Nodel = last; final Node newNode = new Node<>(l, e, null); last = newNode; if (l == null) first = newNode; else l.next = newNode; size++; modCount++; }
就是一个Node持有另个一Node的引用,形成以个链条。
删除元素:
E unlink(Nodex) { // assert x != null; final E element = x.item; final Node next = x.next; final Node prev = x.prev; if (prev == null) { first = next; } else { prev.next = next; x.prev = null; } if (next == null) { last = prev; } else { next.prev = prev; x.next = null; } x.item = null; size--; modCount++; return element; }
先找到元素再赋值为null,并接上前面的。
Vector:
底层用数组实现List接口的另一个类;
特点:重量级,占据更多的系统开销,线程安全;
Vector与ArrayList基本上一致,最大的差别于在一些方法上使用了synchronized关键字,使其变成线程安全。
----------------------------------------------------------------------------------
Set:
无顺序的,元素不可重复(值不相同);
遍历:迭代;
排序:SortedSet
HashSet:
采用哈希算法来实现Set接口;
唯一性保证:重复对象equals方法返回为true;
重复对象hashCode方法返回相同的整数,不同对象hashCode尽量保证不同(提高效率);
构造:
private transient HashMapmap; private static final Object PRESENT = new Object(); public HashSet() { map = new HashMap<>(); }
实际上的HashSet内部的实现为一个HashMap(下面看看HashMap的组成)。
添加元素:
public boolean add(E e) { return map.put(e, PRESENT)==null; }
由源代码块可以看出HashSet添加一个元素时,添加的值为HashMap的Key值,而一个Object对象却为一个Value值。
删除元素:
public boolean remove(Object o) { return map.remove(o)==PRESENT; }
那么HashSet无序不重复的属性则来自于HashMap。
TreeSet:
在元素添加的同时,进行排序。也要给出排序规则;
唯一性保证:根据排序规则,compareTo方法返回为0,就可以认定两个对象中有一个是重复对象。
结构:
private transient NavigableMapm; private static final Object PRESENT = new Object();
----------------------------------------------------------------------------------
Map:
元素是键值对:key唯一不可重复,value可重复;
遍历:先迭代遍历key的集合,再根据key得到value;
SortedMap:元素自动对key排序
HashMap:
轻量级,线程不安全,允许key或者value是null;
构造:
transient Entry[] table; public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); // Find a power of 2 >= initialCapacity int capacity = 1; while (capacity < initialCapacity) capacity <<= 1; this.loadFactor = loadFactor; threshold = (int)(capacity * loadFactor); [color=red]table = new Entry[capacity];[/color] init(); }
从构造方法分可以看出其为一个Entry数组
Entry主要属性:
final K key; V value; Entrynext;
该源码片段可以看出Entry以及key值一旦赋值就无法更改。
添加元素:
public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); for (Entrye = table[i]; e != null; e = e.next) { Object k; if ([color=red]e.hash == hash && ((k = e.key) == key || key.equals(k)[/color])) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
红色部分对于重复对象的比较,使用了key的hashcode,key指向的地址,以及其值是否相等。
容量自增:
void resize(int newCapacity) { Entry[] oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; } Entry[] newTable = new Entry[newCapacity]; transfer(newTable); table = newTable; threshold = (int)(newCapacity * loadFactor); }
Hashtable:
重量级,线程安全,不允许key或者value是null;
从源码可以看出与HashMap很相识,这是Hashmap为其轻量级的实现。
大量带有实际操作性的方法都为synchronized修饰。
Properties:Hashtable的子类,key和value都是String,同样为线程安全。
public synchronized Object setProperty(String key, String value) { return put(key, value); }
TreeMap:
集合是指一个对象可以容纳了多个对象(不是引用),这个集合对象主要用来管理维护一系列相似的对象。