[toc]html
public interface Collection<E>{
// 集合改變返回 true,不然返回 false
boolean add();
boolean addAll();
// 返回一個迭代器
Iterator<E> iterator();
int size();
boolean isEmpty();
// 集合中包含了和 obj 相等的對象,那麼返回 true
boolean contains(Object obj);
// 若是集合中包含 other 集合中的全部元素,那麼返回 true
boolean containsAll(Collect<?> other);
// 從這個集合中刪除等於 obj 的對象,若是有匹配的對象,返回 true
boolean remove(Object obj);
// 從這個集合中刪除 other 中存在的元素,若是這個調用改變了集合,那麼返回 true
boolean removeAll(Collect<?> other);
void clear();
// 從這個集合中刪除全部與 other 這個集合中的元素不一樣的元素,若是這個調用改變了集合,那麼返回 true
boolean retainAll(Collection<?> other);
Object[] toArray();
<T> T[] toArray(T[] a);
}
複製代碼
public interface Iterator<E>{
// 反覆調用,能夠逐個訪問集合中的每一個元素(配合 hasNext() 這個方法)
E next();
boolean hasNext();
// 刪除上次調用 next() 返回的元素,沒有調用 next() 方法,調用 remove() 則會報 IllegalStateException 異常
void remove();
}
複製代碼
Collection<String> c = ....;
Iterator<String> iterator = c.iterator();
while(iterator.hasNext()){
String element = iterator.next();
iterator.remove();
// todo something
}
複製代碼
Collection<String> c = ....;
for(String element : c){
// todo something
}
複製代碼
「for each」 循環能夠與任何實現了 Iterable 接口的對象一塊兒工做java
java.lang.Object
↳ java.util.AbstractCollection<E>
↳ java.util.AbstractList<E>
↳ java.util.ArrayList<E>
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {}
複製代碼
// 將其包裝成線程安全
List list = Collections.synchronizedList(new ArrayList());
複製代碼
JDK 1.6 及以前數組
int newCapacity = (oldCapacity * 3)/2 + 1;
複製代碼
JDK 1.7 及以後安全
int newCapacity = oldCapacity + (oldCapacity >> 1);
複製代碼
JDK 1.8bash
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);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
複製代碼
Object[] toArray()
<T> T[] toArray(T[] contents)
複製代碼
// toArray(T[] contents)調用方式一
public static Integer[] vectorToArray1(ArrayList<Integer> v) {
Integer[] newText = new Integer[v.size()];
v.toArray(newText);
return newText;
}
// toArray(T[] contents)調用方式二。最經常使用!
public static Integer[] vectorToArray2(ArrayList<Integer> v) {
Integer[] newText = (Integer[])v.toArray(new Integer[0]);
return newText;
}
// toArray(T[] contents)調用方式三
public static Integer[] vectorToArray3(ArrayList<Integer> v) {
Integer[] newText = new Integer[v.size()];
Integer[] newStrings = (Integer[])v.toArray(newText);
return newStrings;
}
複製代碼
一種能夠在任意位置進行高效插入及刪除的操做的有序序列數據結構
java.lang.Object
↳ java.util.AbstractCollection<E>
↳ java.util.AbstractList<E>
↳ java.util.AbstractSequentialList<E>
↳ java.util.LinkedList<E>
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
複製代碼
public static void useLinkedListAsLIFO() {
System.out.println("\nuseLinkedListAsLIFO");
// 新建一個LinkedList
LinkedList stack = new LinkedList();
// 將1,2,3,4添加到堆棧中
stack.push("1");
stack.push("2");
stack.push("3");
stack.push("4");
// 打印「棧」
System.out.println("stack:"+stack);
// 刪除「棧頂元素」
System.out.println("stack.pop():"+stack.pop());
// 取出「棧頂元素」
System.out.println("stack.peek():"+stack.peek());
// 打印「棧」
System.out.println("stack:"+stack);
}
複製代碼
public static void useLinkedListAsFIFO() {
System.out.println("\nuseLinkedListAsFIFO");
// 新建一個LinkedList
LinkedList queue = new LinkedList();
// 將10,20,30,40添加到隊列。每次都是插入到末尾
queue.add("10");
queue.add("20");
queue.add("30");
queue.add("40");
// 打印「隊列」
System.out.println("queue:"+queue);
// 刪除(隊列的第一個元素)
System.out.println("queue.remove():"+queue.remove());
// 讀取(隊列的第一個元素)
System.out.println("queue.element():"+queue.element());
// 打印「隊列」
System.out.println("queue:"+queue);
}
複製代碼
HashMap 它是基於 hash 表的 Map 接口實現,以 key-value 的形式存在的,HashMap 老是以 key-value 的形式存在的,系統會經過計算 key 的 hash 值來定位 key-value 的存儲位置的,咱們能夠快速的經過 key 來存取 value;多線程
public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
複製代碼
關於 HashMap 的數據結構,底層的話仍是數組的,只不過數組的每一項就是一個鏈表dom
構造函數的源碼函數
public HashMap(int initialCapacity, float loadFactor) {
//初始容量不能<0
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: "
+ initialCapacity);
//初始容量不能 > 最大容量值,HashMap的最大容量值爲2^30
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
//負載因子不能 < 0
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: "
+ loadFactor);
// 計算出大於 initialCapacity 的最小的 2 的 n 次方值。
int capacity = 1;
while (capacity < initialCapacity)
capacity <<= 1;
this.loadFactor = loadFactor;
//設置HashMap的容量極限,當HashMap的容量達到該極限時就會進行擴容操做
threshold = (int) (capacity * loadFactor);
//初始化table數組
table = new Entry[capacity];
init();
}
複製代碼
Entry 的源碼post
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;
final int hash;
/**
* Creates new entry.
*/
Entry(int h, K k, V v, Entry<K,V> n) {
value = v;
next = n;
key = k;
hash = h;
}
.......
}
複製代碼
Entry 是 HashMap 的內部類,其中包含了 key,value 和 下一個 Entry,以及 hash 值,正由於有這下才構成了數組的項爲一個列表。
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
複製代碼
DEFAULT_INITIAL_CAPACITY*DEFAULT_LOAD_FACTOR
複製代碼
在關鍵字的 hash 地址上已經有了記錄,那麼這就是哈希衝突
複製代碼
public V put(K key, V value) {
//當key爲null,調用putForNullKey方法,保存null與table第一個位置中,這是HashMap容許爲null的緣由
if (key == null)
return putForNullKey(value);
//計算key的hash值
int hash = hash(key.hashCode()); ------(1)
//計算key hash 值在 table 數組中的位置
int i = indexFor(hash, table.length); ------(2)
//從i出開始迭代 e,找到 key 保存的位置
for (Entry<K, V> e = table[i]; e != null; e = e.next) {
Object k;
//判斷該條鏈上是否有hash值相同的(key相同)
//若存在相同,則直接覆蓋value,返回舊value
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value; //舊值 = 新值
e.value = value;
e.recordAccess(this);
return oldValue; //返回舊值
}
}
//修改次數增長1
modCount++;
//將 key、value 添加至i位置處
addEntry(hash, key, value, i);
return null;
}
複製代碼
(1)處代碼實現:技術 hash 值
static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
複製代碼
(2)處代碼實現:根據 hash 值計算出 key 在 table 數組中所對應的位置
static int indexFor(int h, int length) {
return h & (length-1);
}
複製代碼
(3)將節點插入表頭
void addEntry(int hash, K key, V value, int bucketIndex) {
//獲取bucketIndex處的Entry
Entry<K, V> e = table[bucketIndex];
//將新建立的 Entry 放入 bucketIndex 索引處,並讓新的 Entry 指向原來的 Entry
table[bucketIndex] = new Entry<K, V>(hash, key, value, e);
//若HashMap中元素的個數超過極限了,則容量擴大兩倍
if (size++ >= threshold)
resize(2 * table.length);
}
複製代碼
隨着 HashMap 中的元素愈來愈多,發生 hash 衝突的機率愈來愈大,鏈表的長度愈來愈長,查找的效率就愈來愈低;這樣咱們就必須在 HashMap 的某個臨界值進行擴容處理。擴容的方式:從新建立一個新的 table 數組,從新計算 key 的 hash 值,並放入新的 table 數組中,這樣的操做是比較耗時的,若是咱們可以預知 HashMap 中的大小時,咱們能夠指定 HashMap 中的元素個數。
public V get(Object key) {
// 若爲null,調用getForNullKey方法返回相對應的value
if (key == null)
return getForNullKey();
// 根據該 key 的 hashCode 值計算它的 hash 碼
int hash = hash(key.hashCode());
// 取出 table 數組中指定索引處的值
for (Entry<K, V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) {
Object k;
//若搜索的key與查找的key相同,則返回相對應的value
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
return e.value;
}
return null;
}
複製代碼
HashMap 是線程不安全的,咱們能夠經過 Collections 的靜態方法 SynchronizedMap 來獲取線程安全的 HashMap
Map map = Collections.SynchronizedMap(new HashMap<>();
複製代碼
```
/**
* HashMap.Node subclass for normal LinkedHashMap entries.
*/
static class LinkedHashMapEntry<K,V> extends HashMap.Node<K,V> {
LinkedHashMapEntry<K,V> before, after;
LinkedHashMapEntry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
```
複製代碼
// Callbacks to allow LinkedHashMap post-actions
// 訪問元素以後
void afterNodeAccess(Node<K,V> p) { }
// 插入節點以後
void afterNodeInsertion(boolean evict) { }
// 刪除節點以後
void afterNodeRemoval(Node<K,V> p) { }
複製代碼
HashTable 和 HashMap 都實現了 Map 接口,他們的主要區別在於線程安全、速度。