DataContainer-數據容器
概念
一、Collection<E> 集合 Object數組
AbstractCollection
List<E> 索引訪問
Set<E> 唯一存儲
二、Map<K,V> 鍵值映射
CouncurrentMap<K,V>
SortedMap<K,V>
三、Comparable<T>
Array
List<E> 序列 元素可重、存儲有序、N個Null、順序索引
ArrayList 數組列表 線性表-非同步 查詢-索引訪問-非同步
LinkedList 鏈接列表 雙向鏈表 插入、刪除-任意位置
Vector 向量列表 線性表-同步 查詢-索引訪問-同步
Set<E> 集合 元素無重、存儲無序、1個Null
HashSet 無序 HashMap
TreeSet 有序
SortedSet 可選排序
LinkedHashSet HashTable+LinkedList
Map<K,V>
HashTable
HashMap HashTable
TreeMap
SortedMap
LinkedHashSet HashTable+LinkedList
Collection-集合
Collection<E>-集合接口
CollectionS -集合類 差集、並集、拷貝、排序
類型 數據結構 Null值 線程安全 擴容 適用 弱勢
Array 定長數組
ArrayList 可變數組 N 非安全 1.5+1 查改 增刪插[數組拷貝]
LinkedList 雙向鏈表 N 非安全 XXX 增刪插[前後引用] 查改
Deque接口,add,poll提供FIFO隊列操作、堆棧操作、雙端隊列操作
Vector XXXX X 安全
HashMap 數組+單向鏈表 Key:Value = 1:N 非安全 2
HashTable 數組+單向鏈表 不允許 安全 2
TreeMap 自平衡紅黑樹 不允許 非安全
按鍵排序迭代
HashSet 哈希集合 1 非安全
不保證迭代順序
TreeSet 樹集合 1
自動排序[自然排序、定製排序]
LinkedHashSet
特殊順序迭代
List
數據容器 Object數組
ArrayList LinkedList Vector
線程安全 非安全 XXX 安全
數據結構
適用場景 遍歷 插入刪除
ArrayList
//替代元素 返回元素
public E set(int index,E element){
RangeCheck(index); //合法性檢查:索引範圍
E oldValue = (E) elementData[index]; //
elementData[] = element;
return oldValue;
}
//添加元素 返回結果
public boolean add(E e){
ensureCapacity(size+1); //長度+1、確保容量
elementData[size++]=e; //添加
return true;
}
//插入元素 指定位置
public void add(int index,E element){
if(index>size||index<0) //合法性檢查:長度範圍
throw new IndexOutOfBoundsException("Index:"+index+",Size"+size);
ensureCapacity(size+1); //長度+1、確保容量
System.arraycopy(elementData,index,elementData,index+1,size-index);
//數組拷貝,整體移動[向後]
elementData[index] = element;//設定插入
size++;
}
//刪除元素 指定位置
public E remove(int index){
RangeCheck(index); //合法性檢查:索引範圍
modCount++; //修改次數
E oldValue = (E) elementData[index];
int numMoved = size-index-1;
if(numMoved>0) //數組拷貝,整體移動[向前]
System.arraycopu(elementData,index+1,index+1,elementData,inde,numMoved);
elementData[--size] = null;//設定尾部null
return oldValue; //返回舊元素
}
//擴容1.5+1
public void ensureCapaity(int minCapacity){
modCount++;
int oldCapacity = elementData.length; //容量
if(minCapacity>oldCapacity){
int newCapacity = (oldCapacity*3)/2+1;
if(newCapacity < minCapacity)
newCapacity = minCapacity;
elementData = Arrays.copyOf(elementData,newCapacity);
//拷貝原有元素
}
}
LinkedList
雙端隊列 previous—Entry—next
private transient Entry<E> header = new Entry<>();
private static class Entry<E>{
E element;
Entry<E> next;
Entry<E> previous;
}
//構造方法 目標對象paramE放置在paramEntry1之前,paramEntry2之後
Entry(E paramE,Entry<E> paramEntry1,Entry<E> paramEntry2){
this.element = paramE;
this.next = paramEntry1;
this.previous = paramEntry2;
}
//查詢
private Entry<E> entry(int paramInt){
if((paramInt<0)||(paramInt>=this.size)){ //合法檢查:範圍檢查
throw new IndexOutOfBoundsException("Index:"+paramInt+",Size:"+this.zize); }
Entry localEntry = this.header; //查找:從頭部開始————>雙向環
int i; //最多遍歷size/2個元素
if(paramInt<this.size>>1){ //判斷位置?中間位置
for(i=0;i<=paramInt;i++) //頭部:向後查找
localEntry = localEntry.next;
} else {
for(i=this.size;i>paramInt;i++) //尾部:向前查找
localEntry = localEntry.previous;
}
return localEntry;
}
/*插入
*添加元素:paramE
*目標對象:paramEntry
*/
private Entry<E> addBefore(E paramE,Entry<E> paramEntry){
//實例化新節點 設置前節點、後節點
//兩點確定一條直線
Entry localEntry = new Entry(paramE,paramEntry,paramEntry.previous);
localEntry.previous.next = localEntry; //前節點
localEntry.next.previous = localEntry; //後節點
this.size += 1;
this.moCount += 1;
return localEntry;
}
//添加 根據位置
public void add(int index,E element){
addBefore(element,(index==size?header:entry(index)));
}
//隊首添加
public void addFirst(E paramE){ addBefore(paramE,this.header.next);}
//隊尾添加
public void addLast(E paramE){ addBefore(paramE,this.header);}
//刪除
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;
e.next = e.previous = null; //解除引用 刪除節點 前後設爲null
size--;
modCount++;
return result
}
public E remove(){
return removeFirst();
}
//刪除
public E remove(int index){ return remove(entry(index));}
//刪除隊首
public E removeFirst(){ return remove(header.next);}
//刪除隊尾
public E removeLast(){ return remove(header.previous);}
Set
數據結構 Map
HashSet
//底層使用HashMap保存HashSet元素
private transient HashMap<E,Object> map;
//定義虛擬的Object對象:HashMap的Value
private static final Object PRESENT = NEW Object();
//添加 藉助HashMap的add方法
//HashMap的add方法,返回key之前的value值
//如果爲null則說明之前尚未添加key,即HashSet可以添加該元素
public boolean add(E e){
return map.put(e,PRESENT) == null;
}
//查找 藉助HashMap的contain方法
public boolean contain(Object o){
return map.containsKey(o);
}
TreeSet
遍歷方式 自然順序、中序遍歷
數據結構 紅黑樹
LinkedHashSet
遍歷方式 自然順序、中序遍歷
數據結構 鏈表
Map
存儲數據 Entry數組
存儲原理 位置(數組下標)由key的哈希值與數組長度計算而來。
如果數組當前下標已有值,則將數組當前下標的值指向新添加的Entry對象。
哈希碰撞
Hashtable HashMap TreeMap LinkedHashMap ConcurrentHashMap
默認容量 11 16
容量要求 無 2的整數次冪
擴容方式 *2+1 *2
數據結構 XXXX XXXX 紅黑樹 雙向鏈表
順序特性 無序 無序 有序
線程安全 安全 不安全
多線程情況 V慢 V快 XXX V中
Hash運算 位置索引取模 長度取模
Null值 K:V=1:N K:V=0:0 K:V=0:0
迭代器 Enumeration Iterator
方法 contain() containKey()
containValue()
適用場景
ConcurrentHashMap
鎖分段技術
[1]首先將Map存放的數據分成一段一段的存儲方式,
[2]然後給每一段數據分配一把鎖,
[3]當一個線程佔用鎖訪問其中一個段的數據時,其他段的數據也能被其他線程訪問。
樹化 JDK1.8
TreeMap
1.數據結構 自平衡紅黑二叉查找樹
Entry節點、Key鍵、Value值、Left左孩子、Right右孩子、Parent父節點、Color顏色
2.排序 comparator比較 Entry的Key節點
3.優點 空間利用率高、性能穩定(O logn)
4.特性 數據大小 左節點<自節點<右節點
排序方式 [1]自然排序 默認升序
[2]定製排序 可自定義
HashMap
== 數值大小
equals() 數據內容
hashCode() 編碼地址
//數據結構
transient Entry[] table;
static class Entry<K,V> implements Map.Entry<K,V>{
final K key;
V value;
Entry<K,V> next;
final int hash;
...
}
//一、存入
public V put(K key,V value){
if(key == null) // null鍵視爲相同的鍵
return putForNullKey(value); //根據key的keycode重新計算hash值
int hash = hash(key.hashCode()); //搜索指定hash值在對應table中的索引
int i = indexFor(hash,table.length);
//如果i索引出的Entry不爲null,循環遍歷,下一個元素
for(Entry<>=table[i]; e!=null; e=e.next){ //數組
Object k;
//鏈表
if(e.hash == hash
&& ((k=e.key)==key||key.equals(k))){
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash,key,value,i); //鏈表Entry 插入
}
//1.插入數組
//hash函數,加入高位計算,防止低位不變,高位變化時,造成hash衝突
static int hash(int h){
h ^=(h>>>20)^(h>>>12);
return h^(h>>>7)^(h>>>4);
}
//2.插入鏈表
void addEntry(int hash,K key,V value,int bucketIndex){
Entry<K,V> e = table[bucketIndex]; //獲取Entry bucketIndex索引
table[bucketIndex] = new Entry<K,V>(hash,key,value,e); //
if(size==>threshold) //判斷容量 Map中的key-value
resize(2*table.length);
}
//查詢 根據hash值查找對應的table位置
static int indexFor(int h,int length){
return h & (length-1);
}
//二、取出 get
public V get(Object key){
if(key == null) //合法檢查:null
return getForNullKey();
int hash = hash(key.hashCode());
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.equals(k)))
return e.value;
}
return null;
}
LinkedHashMap
//添加 addEntry
void addEntry(int hash,K key,V value,int bucketIndex){
//調用create方法,將新元素以雙向鏈表的形式加入到映射中
createEntry(hash,key,value,bucketIndex);
Entry<K,V> eldest = header.after;
if(removeEldestEntry(eldest)){ //隊首 正向添加
removeEntryForKey(eldest.key);
} else{
if(size >= threshold) //隊尾 逆向添加
resize(2*table.length);
}
}
//創建節點對象
void createEntry(int hash,K key,V value,int bucketIndex){
HashMap.Entry<K,V> old = table[bucketIndex];
Entry<K,V> e = new Entry<K,V>();
table[bucketIndex] = e;
//調用元素的addBefore方法,將元素加入到雙向鏈接列表
e.addBefore(header);
size++;
}
//二、獲取 get
public V get(Object key){
//調用父類HashMap的getEntry()方法
Entry<K,V> e = (Entry<K,V>) getEntry();
if(e == null)
return null;
e.recordAccess(this); //記錄訪問殊勳
return e.value
}
void recordAccess(HashMap<K,V> m){
LinkedHashMap<K,V> Im = (LinkedHashMap<>K,V) m;
//如果定義了LinkedHashMap的迭代順序爲訪問順序
//則刪除以前位置上的元素,並將最新訪問的元素添加到鏈表表頭
if(Im.accessOrder){
Im.modCount++;
remove();
addBefore(Im.header);
}
}