// Collection 接口在其源碼中的定義: * 1. Collection 是集合層次結構中的根接口 * 2. 一個 Collection 表明 一組對象(objects),這些對象稱爲其元素(elements) * 3. 一些 Collection 容許有重複的元素,而另外一些 Collection 不容許有重複的元素 * 4. 一些 Collection 的元素是有序的,而另外一些 Collection 是無序的 * 5. JDK 沒有提供任何直接(direct)實現 Collection 的類 * 6. JDK 只提供了繼承 Collection 的「子接口」(List 和 Set)的實現類 * -Set 中的元素沒有順序且不能夠重複 * -List 中的元素有順序且能夠重複 * -Map 接口定義了存儲 「鍵(key)- 值(value)映射對」 的方法,鍵(key)不能重複,重寫 hashCode() 和 equals() 方法! * * * 接口 Collection * / \ * * 接口 Set List Map * | / \ | * * 類 HashSet ArrayList LinkedList HashMap // 談到 Collection 接口,咱們不得不區別一下 Collections 類 // Collections 是一個類,不能實例化,是一個工具類,它包含各類有關集合操做的靜態(static)多態方法,好比 sort、search、shuffle 以及線程安全等操做 public class Collections { // 私有化構造器,因此不能被實例化 private Collections() { } ... }
1. ArrayList 是 List 接口的實現類,並繼承於 AbstractList(AbstractList 繼承於 AbstractCollection,而且實現了大部分 List 接口) 2. ArrayList 的底層實現是動態數組(屬於數據結構中的可擴容的線性表),線程不安全,效率高 // 建立 List list = new ArrayList(); // 經常使用方法 list.size();// 返回元素的數量 list.isEmpty(); list.add(element); list.add(index, element);// 在指定位置添加元素 list.remove(index);// 刪除指定索引的元素,並返回該元素內容 list.remove(element);// 刪除指定元素,刪除成功返回 true list.get(index);// 獲取指定位置的元素 list.toArray();// 返回一個包含列表中的全部元素的數組 list.contains(element);// 判斷是否包含指定元素 list.indexOf(element);// 返回指定元素所在的第一個位置,沒找到返回 -1 list.lastIndexOf(element);// 返回指定元素所在的最後一個位置 list.clear();// 刪除全部元素 // 爲了更深刻了解 ArrayList,咱們來分析一下 ArrayList 的部分源碼
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { private static final int DEFAULT_CAPACITY = 10;// 默認容量爲 10 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;// 最大容量 private static final Object[] EMPTY_ELEMENTDATA = {}; private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; transient Object[] elementData;// 可見底層是 Object 對象數組 private int size;// 包含元素的數量 // 無參構造器,對象數組默認爲空 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } // 有參構造器,用於初始化數組容量 public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } // 返回所包含元素的數量 public int size() { return size; } // 判斷對象數組是否爲空 public boolean isEmpty() { return size == 0; } // 返回一個包含列表中的全部元素的數組 public Object[] toArray() { return Arrays.copyOf(elementData, 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; return oldValue; } // 添加元素 public boolean add(E e) { ensureCapacityInternal(size + 1);// 判斷是否須要擴容 elementData[size++] = e; return true; } // 判斷是否須要擴容 private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; if (minCapacity - elementData.length > 0) grow(minCapacity); } // 擴容方法 private void grow(int minCapacity) { 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); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } ... }
1. LinkedList 是 List 接口的實現類,並繼承於 AbstractSequentialList(AbstractSequentialList 繼承於 AbstractList,提供了對數據元素的鏈式訪問而不是隨機訪問) 2. LinkedList 的底層實現是鏈表(屬於數據結構中的雙向鏈表),線程不安全,效率高 // 建立 List link = new LinkedList(); // 經常使用方法 link.size(); link.getFirst();// 返回第一個節點的元素 link.getLast();// 返回最後一個節點的元素 link.get(index);// 返回指定位置的元素 link.contain(element);// 判斷鏈表中是否有指定元素 link.addFirst(element);// 從鏈表頭部插入元素,無返回值 link.add(element); // 從鏈表尾部插入元素,插入成功返回 true link.add(index, element);// 在指定位置插入元素,無返回值 link.remove(element); // 刪除指定元素,刪除成功返回 true link.remove(index);// 刪除指定位置的元素,刪除成功返回被刪除元素 link.addAll(Collection);// 添加指定集合 link.clear();// 清空鏈表,釋放節點空間 // 爲了更深刻了解 LinkedList,咱們來分析一下 LinkedList 的部分源碼
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable { // 用私有靜態內部類定義鏈表的節點對象 private static class Node<E> { E item; // 存放元素內容 Node<E> next;// 指向下一個節點 Node<E> prev;// 指向前一個節點 //有參構造器 Node(Node<E> prev, E element, Node<E> next) { this.item = element; this.next = next; this.prev = prev; } } transient int size = 0;// 元素的數量 transient Node<E> first;// 指向鏈表的第一個節點 transient Node<E> last;// 指向鏈表的最後一個節點 public LinkedList() { } // 有參構造器,用於構造包含指定集合的鏈表 public LinkedList(Collection<? extends E> c) { this(); addAll(c);// 添加指定集合 } // 返回元素的數量 public int size() { return size; } // 在鏈表的頭部插入元素 public void addFirst(E e) { linkFirst(e); } private void linkFirst(E e) { final Node<E> f = first; final Node<E> newNode = new Node<>(null, e, f); first = newNode; if (f == null) last = newNode; else f.prev = newNode; size++; modCount++; } // 在鏈表的尾部插入元素 public boolean add(E e) { linkLast(e); return true; } void linkLast(E e) { final Node<E> l = last; final Node<E> newNode = new Node<>(l, e, null); last = newNode; if (l == null) first = newNode; else l.next = newNode; size++; modCount++; } // 刪除元素 public boolean remove(Object o) { if (o == null) { for (Node<E> x = first; x != null; x = x.next) { if (x.item == null) { unlink(x); return true; } } } else { for (Node<E> x = first; x != null; x = x.next) { if (o.equals(x.item)) { unlink(x); return true; } } } return false; } E unlink(Node<E> x) { // assert x != null; final E element = x.item; final Node<E> next = x.next; final Node<E> 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; } // 清空鏈表 public void clear() { for (Node<E> x = first; x != null; ) { Node<E> next = x.next; x.item = null; x.next = null; x.prev = null; x = next; } first = last = null; size = 0; modCount++; } }
1. HashMap 是 Map 接口的實現類,並繼承於 AbstractMap(AbstractMap 是 Map 接口的抽象實現類,而且實現了大部分 Map 接口) 2. HashMap 的底層實現:哈希表+鏈表(屬於數據結構中的鄰接表) // 建立 Map map = new HashMap(); // 經常使用方法 map.put(k,v);// 添加鍵值對,若是 key 已存在,則覆蓋 value,並返回被覆蓋的 value;不存在,則返回 null map.putAll(map02);// 添加指定的 map 集合 map.remove(k);// 刪除指定 key 的節點,並返回 value map.get(k);// 獲取指定 key 的 value map.containsKey(k);// 判斷是否含有指定 key 的節點 map.containsValue(v);// 判斷是否含有指定 value 的節點 map.size();// 返回鍵值對的數量 map.values();//獲取全部 value,返回值類型 Collection<valueType> map.keySet(); //獲取全部 key,返回值類型 Set<keyType> map.entrySet();// 獲取全部 key 和 value,返回值類型 Set<Entry<keyType, valueType>> map.clear();// 清空 map 裏的全部鍵值對 // 爲了更深刻了解 HashMap,咱們來分析一下 HashMap 的部分源碼
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;// 默認最小容量 MUST be a power of two. aka 16 static final int MAXIMUM_CAPACITY = 1 << 30;// 默認最大容量 static final float DEFAULT_LOAD_FACTOR = 0.75f;// 默認負載因子 // 用靜態內部類定義鏈表的節點對象 static class Node<K,V> implements Map.Entry<K,V> { final int hash;// 存放 hashCode final K key;// 存放 key V value; // 存放 value Node<K,V> next;// 指向下個節點 // 有參構造器 Node(int hash, K key, V value, Node<K,V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } public final K getKey() { return key; } public final V getValue() { return value; } public final String toString() { return key + "=" + value; } /* 使用本身定義的 hashCode()方法 這裏給出 java.util.Objects 中定義的 hashCode()方法 public static int hashCode(Object o) { return o != null ? o.hashCode() : 0; } */ public final int hashCode() { return Objects.hashCode(key) ^ Objects.hashCode(value); } public final V setValue(V newValue) { V oldValue = value; value = newValue; return oldValue; } /* 使用本身定義的 equals()方法 這裏給出 java.util.Objects 中定義的 equals()方法 public static boolean equals(Object a, Object b) { return (a == b) || (a != null && a.equals(b)); } */ public final boolean equals(Object o) { if (o == this) return true; if (o instanceof Map.Entry) { Map.Entry<?,?> e = (Map.Entry<?,?>)o; if (Objects.equals(key, e.getKey()) && Objects.equals(value, e.getValue())) return true; } return false; } } transient Node<K,V>[] table;// 聲明哈希表 transient int size;// 元素的數量 final float loadFactor;// 負載因子 // 無參構造器 public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; } public int size() { return size; } public boolean isEmpty() { return size == 0; } // 定義了本身的 hash()方法 static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } /* 添加鍵值對 咱們先在這給出 java.lang.Object 的 equals()方法 public boolean equals(Object obj) { return (this == obj); } 因此,咱們在作 key 的比較時,要根據本身的需求重寫 equals()方法 */ public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; // 若是哈希表爲空,初始化哈希表 if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; // 若是 hash(key) 對應哈希表位置爲 null,直接存放該節點 if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node<K,V> e; K k; // 若是 hash(key) 對應哈希表位置存放的節點 key 等於 咱們要添加的鍵值對的 key,則直接覆蓋 value if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; // 若是是樹節點的操做 else if (p instanceof TreeNode) e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); // 若是 hash(key) 對應哈希表位置存放的節點 key 不等於 咱們要添加的鍵值對的 key,則往下尋找,若是有相等的,覆蓋 value,沒有則在最後一個節點後添加新節點存放 else { for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; } // 有參構造器,使用與指定的 Map 相同的映射,構造一個新的 HashMap,新的 HashMap 內包含了指定 map 的全部元素 public HashMap(Map<? extends K, ? extends V> m) { this.loadFactor = DEFAULT_LOAD_FACTOR; putMapEntries(m, false); } final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) { int s = m.size(); if (s > 0) { if (table == null) { // pre-size float ft = ((float)s / loadFactor) + 1.0F; int t = ((ft < (float)MAXIMUM_CAPACITY) ? (int)ft : MAXIMUM_CAPACITY); if (t > threshold) threshold = tableSizeFor(t); } else if (s > threshold) resize(); for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) { K key = e.getKey(); V value = e.getValue(); putVal(hash(key), key, value, false, evict); } } } // 獲取指定 key 的 value public V get(Object key) { Node<K,V> e; return (e = getNode(hash(key), key)) == null ? null : e.value; } final Node<K,V> getNode(int hash, Object key) { Node<K,V>[] tab; Node<K,V> first, e; int n; K k; if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) { if (first.hash == hash && // always check first node ((k = first.key) == key || (key != null && key.equals(k)))) return first; if ((e = first.next) != null) { if (first instanceof TreeNode) return ((TreeNode<K,V>)first).getTreeNode(hash, key); do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } while ((e = e.next) != null); } } return null; } // 是否存在指定 key public boolean containsKey(Object key) { return getNode(hash(key), key) != null; } // 刪除指定 key 的鍵值對,並返回 value public V remove(Object key) { Node<K,V> e; return (e = removeNode(hash(key), key, null, false, true)) == null ? null : e.value; } final Node<K,V> removeNode(int hash, Object key, Object value, boolean matchValue, boolean movable) { Node<K,V>[] tab; Node<K,V> p; int n, index; if ((tab = table) != null && (n = tab.length) > 0 && (p = tab[index = (n - 1) & hash]) != null) { Node<K,V> node = null, e; K k; V v; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) node = p; else if ((e = p.next) != null) { if (p instanceof TreeNode) node = ((TreeNode<K,V>)p).getTreeNode(hash, key); else { do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { node = e; break; } p = e; } while ((e = e.next) != null); } } if (node != null && (!matchValue || (v = node.value) == value || (value != null && value.equals(v)))) { if (node instanceof TreeNode) ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable); else if (node == p) tab[index] = node.next; else p.next = node.next; ++modCount; --size; afterNodeRemoval(node); return node; } } return null; } // 清空 public void clear() { Node<K,V>[] tab; modCount++; if ((tab = table) != null && size > 0) { size = 0; for (int i = 0; i < tab.length; ++i) tab[i] = null; } } }
1. HashSet 是 Set 接口的實現類,並繼承於 AbstractSet(AbstractSet 繼承於 AbstractCollection,而且實現了大部分 Set 接口) 2. HashSet 的底層實現:利用 「HashMap 鍵惟一」 的特性 // 建立 Set set = new HashSet(); // 經常使用方法 set.size();// 返回元素的數量 set.isEmpty(); set.add(e);// 添加元素,添加成功返回 true,不然返回 false set.remove(e);// 刪除指定元素,刪除成功返回 true set.contains(e);// 判斷指定元素是否已存在 set.clear();// 清空 set 裏的全部元素 // 爲了更深刻了解 HashSet,咱們來分析一下 HashSet 的部分源碼
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable { private transient HashMap<E,Object> map;// 哇,直接就用了 HashMap private static final Object PRESENT = new Object();// 建立一個 Object 對象常量,其實就是用來填充 HashMap 的 value public HashSet() { map = new HashMap<>(); } public int size() { return map.size(); } public boolean isEmpty() { return map.isEmpty(); } public boolean contains(Object o) { return map.containsKey(o); } public boolean add(E e) { // 當添加元素 e 已經存在時,即對應的 map 裏的 key 存在,則 map 的 put()方法會返回被覆蓋的 value,這個 value 就是 PRESENT,不等於 null,故返回 false return map.put(e, PRESENT)==null; } public boolean remove(Object o) { return map.remove(o)==PRESENT; } public void clear() { map.clear(); } }
1.全部實現了 Collection 接口的容器類都有一個 iterator() 方法,用來返回一個實現了 Iterator 接口的對象 2.迭代器使遍歷操做更加方便 3.java.util.Iterator 接口定義了以下方法: * boolean hasNext();// 判斷是否有下一個節點 * Object next();// 返回遊標(cursor)當前位置的元素,而且遊標(cursor)指向下一個位置 * void remove();// 刪除遊標左邊(lastRet)的元素,在執行完 next()方法 以後該操做只能執行一次,由於每次執行 remove()方法後 lastRet 都會置爲 -1;只有當再次使用 next()方法後,纔會給 lastRet 從新賦值 // 下面給出 ArrayList 的遍歷操做,LinkedList、HashMap、HashSet 的遍歷操做都相似,須要注意的是 Map 和 Set 是用 哈希表+鏈表 實現的,因此不能使用第一種遍歷方式(索引遍歷) public class Traversal { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("aaa"); list.add("bbb"); list.add("ccc"); //遍歷方式一 for(int i=0;i<list.size();i++) System.out.println(list.get(i)); //遍歷方式二 for(String li : list) System.out.println(li); //遍歷方式三 for(Iterator<String> iterator = list.iterator();iterator.hasNext();) System.out.println(iterator.next()); //遍歷方式四 Iterator<String> iterator = list.iterator(); while(iterator.hasNext()) System.out.println(iterator.next()); } }