日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

16、java中的集合(3)

發布時間:2023/12/3 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 16、java中的集合(3) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?????? 說一下雙列集合,頂級接口是Map,實現類有HashMap、LinkedHashMap、TreeMap、HashTable等,使用鍵值對的格式存儲數據,鍵不可以重復,值可以重復。接下來對實現類做一下詳細介紹。

?????? HashMap是最常用的Map集合,它所依賴的數據結構是散列表還有紅黑樹,添加元素時,現根據添加鍵值對的key去得到對應的hash值,然后根據hash值和數組的長度確定key在數組中對應的下標位置,然后根據散列是否沖突的原理進行數據添加或者替換(具體分析如下),添加的元素不會進行排序,并且是無序集合。當獲取元素時也是根據key鍵所對應的hash值進行查找的,依賴于數組進行查找,可以達到O(1)的效果,HashMap可以被克隆和序列化,是線程不安全的集合。具體分析如下:

//HashMap對象可被克隆、被序列化 public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {//-------------------------------------- 變量 -------------------------------------////哈希表transient Node<K,V>[] table;transient Set<Map.Entry<K,V>> entrySet;//map中鍵值對的個數,集合的容量transient int size;//修改次數transient int modCount;//閾值。要調整大小的下一個大小值(容量*負載系數)int threshold;//哈希表的負載因子final float loadFactor;//默認的初始容量,必須是2的n次冪//計算結點插入位置時才會取決于hash值,并且保證hash值小于數組長度static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;//最大容量static final int MAXIMUM_CAPACITY = 1 << 30;//默認的加載因子static final float DEFAULT_LOAD_FACTOR = 0.75f;//使用樹而不是列表的計數閾值,當向至少有這么多節點的容器中添加元素時,容器被轉換為樹。其實一般用到的不多static final int TREEIFY_THRESHOLD = 8;//調整大小的計數閾值。操作次數應小于UNTREEIFY_THRESHOLDstatic final int UNTREEIFY_THRESHOLD = 6;//將鏈表樹狀化的最小哈希表容量,就是哈希表中達到一定數據時才有必要將鏈表轉化成樹static final int MIN_TREEIFY_CAPACITY = 64;//基本hash bin結點(就是哈希表中鏈表中的結點)static class Node<K,V> implements Map.Entry<K,V> {final int hash;//記錄hash值final K key;//鍵V 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; }public final int hashCode() {return Objects.hashCode(key) ^ Objects.hashCode(value);}public final V setValue(V newValue) {V oldValue = value;value = newValue;return oldValue;}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;}}//-------------------------------------- 靜態的公用方法------------------////重要函數,計算hash值static final int hash(Object key) {int h;//key.hashCode():返回key的哈希碼值與哈希值的高16位進行異或運算//使得位置盡量分散return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}//只有傳入的對象的運行時類型實現了Comparable才會被返回,否則返回nullstatic Class<?> comparableClassFor(Object x) {//判斷當前對象是否實現了比較器接口if (x instanceof Comparable) {Class<?> c; Type[] ts, as; Type t; ParameterizedType p;if ((c = x.getClass()) == String.class)return c;if ((ts = c.getGenericInterfaces()) != null) {for (int i = 0; i < ts.length; ++i) {if (((t = ts[i]) instanceof ParameterizedType) && ((p = (ParameterizedType)t).getRawType() == Comparable.class) &&(as = p.getActualTypeArguments()) != null &&as.length == 1 && as[0] == c)return c;}}}return null;}//只有傳入的對象x和kc的類型相同時才進行比較@SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparablestatic int compareComparables(Class<?> kc, Object k, Object x) {return (x == null || x.getClass() != kc ? 0 :((Comparable)k).compareTo(x));}//返回一個最接近2的冪并且大于cap的整數static final int tableSizeFor(int cap) {int n = cap - 1;n |= n >>> 1;n |= n >>> 2;n |= n >>> 4;n |= n >>> 8;n |= n >>> 16;return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;}//-------------------------------------- 構造方法-------------------////根據初始大小和負載因子創建實例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);this.loadFactor = loadFactor;//將最接近2的冪并且大于initialCapacity的整數作為閾值this.threshold = tableSizeFor(initialCapacity);}//根據初始大小和負載因子創建實例public HashMap(int initialCapacity) {this(initialCapacity, DEFAULT_LOAD_FACTOR);}public HashMap() {this.loadFactor = DEFAULT_LOAD_FACTOR;}//-------------------------------------- 功能方法-------------------////集合中鍵值對個數public int size() {return size;} //-------------------------------------- 獲取方法 ------------------// //根據鍵獲取值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;//如果當前哈希表不為空 && 哈希表中的鍵值對個數大于0 && key所對應位置上的值不為null則繼續進行//(n - 1) & hash:用來獲取key的hash值對應數組的下標//n = tab.length n-1則一定小于數組的長度,并且數組的長度為2的n次冪//與hash值做與運算則可以保證key值對應的hash值和數組的下標有關系并且不大于數組的長度,當n=16時,如下://00000000 00010000 十進制減去1,則得到 00000000 00001111 ,所以與hash做與運算,則得到的下標值是根據哈希值得到的并且一定小于16//00000000 00001111//00000010 10110101 &//-------------------------//00000000 00000101//這也是為什么數組的大小一定要是2的n次冪的原因if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) {//如果結點first的hash值和key值均相等則可確定key對應的結點就是first,直接返回if (first.hash == hash && ((k = first.key) == key || (key != null && key.equals(k)))){ return first;} //key不相等,如果first結點存在后繼結點,則繼續程序if ((e = first.next) != null) {//如果first是樹結點,則按著樹的規則獲取值if (first instanceof TreeNode)return ((TreeNode<K,V>)first).getTreeNode(hash, key);//如果first不是樹結點,則遍歷鏈表的每一個結點,key相同時,返回對應值do {if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))return e;} while ((e = e.next) != null);}}return null;}//-------------------------------------- 添加方法 ------------------// //添加鍵值對(修改鍵對應的值)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值獲取指定位置上的value,如果value==null,說明沒有hash沖突,則直接添加此結點if ((p = tab[i = (n - 1) & hash]) == null){tab[i] = newNode(hash, key, value, null);}else {//存在hash沖突Node<K,V> e; K k;//key相同,則覆蓋之前的key所對應的valueif (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);}else {//存在沖突,使用鏈表的方式解決沖突,則遍歷鏈表,如果存在相同的key,則覆蓋vlaue,不存在則添加到末端for (int binCount = 0; ; ++binCount) {if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);//判斷是否需要將鏈表轉成紅黑樹if (binCount >= TREEIFY_THRESHOLD - 1) {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 keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e);return oldValue;}}++modCount;if (++size > threshold)//如果哈希表中的鍵值對個數已經達到了閾值,則需要擴容resize();afterNodeInsertion(evict);return null;}//初始化哈希表或者對哈希表進行擴容final Node<K,V>[] resize() {Node<K,V>[] oldTab = table;int oldCap = (oldTab == null) ? 0 : oldTab.length;int oldThr = threshold;int newCap, newThr = 0;//如果舊的數組長度大于0if (oldCap > 0) {//如果數組長度已經達到最大值if (oldCap >= MAXIMUM_CAPACITY) {threshold = Integer.MAX_VALUE;return oldTab;}//如果舊的數組長度未達到最大值,則將舊的數組的長度擴展一倍作為新數組的長度else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY)newThr = oldThr << 1;} else if (oldThr > 0){newCap = oldThr;} else {//數組為空,初始化數組長度和閾值newCap = DEFAULT_INITIAL_CAPACITY;newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);}//如果新的散列的閾值等于0if (newThr == 0) {//閾值 = 數組長度 * 負載因子float ft = (float)newCap * loadFactor;newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? (int)ft : Integer.MAX_VALUE);}threshold = newThr;@SuppressWarnings({"rawtypes","unchecked"})Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];//新創建一個數組table = newTab;//如果舊的數組中有值,則將值按著如下規則復制到新的數組中if (oldTab != null) {for (int j = 0; j < oldCap; ++j) {Node<K,V> e;if ((e = oldTab[j]) != null) {oldTab[j] = null;if (e.next == null){//沒有后繼結點,沒有沖突,直接添加newTab[e.hash & (newCap - 1)] = e;} else if (e instanceof TreeNode){//存在沖突,已經按著紅黑樹進行存儲((TreeNode<K,V>)e).split(this, newTab, j, oldCap);} else { //存在沖突,使用鏈表結構存儲//重新散列,并不是將鏈表復制過去Node<K,V> loHead = null, loTail = null;Node<K,V> hiHead = null, hiTail = null;Node<K,V> next;do {next = e.next;if ((e.hash & oldCap) == 0) {if (loTail == null)loHead = e;elseloTail.next = e;loTail = e;}else {if (hiTail == null)hiHead = e;elsehiTail.next = e;hiTail = e;}} while ((e = next) != null);if (loTail != null) {loTail.next = null;newTab[j] = loHead;}if (hiTail != null) {hiTail.next = null;newTab[j + oldCap] = hiHead;}}}}}return newTab;}//將鏈表轉換成紅黑樹final void treeifyBin(Node<K,V>[] tab, int hash) {int n, index; Node<K,V> e;//如果哈希表中的數組為空,或者哈希表的大小還未達到需要轉換沖紅黑樹的容量,則只是初始化或者擴容if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY){resize();} else if ((e = tab[index = (n - 1) & hash]) != null) {//鏈表轉成紅黑樹TreeNode<K,V> hd = null, tl = null;do {TreeNode<K,V> p = replacementTreeNode(e, null);if (tl == null)hd = p;else {p.prev = tl;tl.next = p;}tl = p;} while ((e = e.next) != null);if ((tab[index] = hd) != null){hd.treeify(tab);} }}//-------------------------------------- 刪除方法 -----------------// //根據key刪除鍵值對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;//如果key的hash碼所對應數組下標位置上存在值,則繼續程序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;//如果hash值相同,并且key相同,則說明沒有沖突,獲取結點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);}}//如果結點不為空,則說明存在key對應的結點,則刪除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;}//-------------------------------------- 遍歷操作 --------------------// //獲取哈希表中所有鍵值對的keypublic Set<K> keySet() {Set<K> ks = keySet;if (ks == null) {ks = new KeySet();keySet = ks;}return ks;}final class KeySet extends AbstractSet<K> {public final int size() { return size; }public final void clear() { HashMap.this.clear(); }public final Iterator<K> iterator() { return new KeyIterator(); }public final boolean contains(Object o) { return containsKey(o); }public final boolean remove(Object key) {return removeNode(hash(key), key, null, false, true) != null;}public final Spliterator<K> spliterator() {return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);}public final void forEach(Consumer<? super K> action) {Node<K,V>[] tab;if (action == null)throw new NullPointerException();if (size > 0 && (tab = table) != null) {int mc = modCount;for (int i = 0; i < tab.length; ++i) {for (Node<K,V> e = tab[i]; e != null; e = e.next)action.accept(e.key);}if (modCount != mc)throw new ConcurrentModificationException();}}}//獲取hash表中所有的valuepublic Collection<V> values() {Collection<V> vs = values;if (vs == null) {vs = new Values();values = vs;}return vs;}final class Values extends AbstractCollection<V> {public final int size() { return size; }public final void clear() { HashMap.this.clear(); }public final Iterator<V> iterator() { return new ValueIterator(); }public final boolean contains(Object o) { return containsValue(o); }public final Spliterator<V> spliterator() {return new ValueSpliterator<>(HashMap.this, 0, -1, 0, 0);}public final void forEach(Consumer<? super V> action) {Node<K,V>[] tab;if (action == null)throw new NullPointerException();if (size > 0 && (tab = table) != null) {int mc = modCount;for (int i = 0; i < tab.length; ++i) {for (Node<K,V> e = tab[i]; e != null; e = e.next)action.accept(e.value);}if (modCount != mc)throw new ConcurrentModificationException();}}}//將hash表中所有的鍵值鍵值對放到一個set集合中public Set<Map.Entry<K,V>> entrySet() {Set<Map.Entry<K,V>> es;return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;}final class EntrySet extends AbstractSet<Map.Entry<K,V>> {public final int size() { return size; }public final void clear() { HashMap.this.clear(); }public final Iterator<Map.Entry<K,V>> iterator() {return new EntryIterator();}public final boolean contains(Object o) {if (!(o instanceof Map.Entry))return false;Map.Entry<?,?> e = (Map.Entry<?,?>) o;Object key = e.getKey();Node<K,V> candidate = getNode(hash(key), key);return candidate != null && candidate.equals(e);}public final boolean remove(Object o) {if (o instanceof Map.Entry) {Map.Entry<?,?> e = (Map.Entry<?,?>) o;Object key = e.getKey();Object value = e.getValue();return removeNode(hash(key), key, value, true, true) != null;}return false;}public final Spliterator<Map.Entry<K,V>> spliterator() {return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);}public final void forEach(Consumer<? super Map.Entry<K,V>> action) {Node<K,V>[] tab;if (action == null)throw new NullPointerException();if (size > 0 && (tab = table) != null) {int mc = modCount;for (int i = 0; i < tab.length; ++i) {for (Node<K,V> e = tab[i]; e != null; e = e.next)action.accept(e);}if (modCount != mc)throw new ConcurrentModificationException();}}}//-------------------------------------- 克隆操作 -------------------// @SuppressWarnings("unchecked")@Overridepublic Object clone() {HashMap<K,V> result;try {result = (HashMap<K,V>)super.clone();} catch (CloneNotSupportedException e) {throw new InternalError(e);}result.reinitialize();result.putMapEntries(this, false);return result;}//-------------------------------------- 序列化操作 -----------------////序列化private void writeObject(java.io.ObjectOutputStream s)throws IOException {//刪除具體代碼}//反序列化private void readObject(java.io.ObjectInputStream s)throws IOException, ClassNotFoundException {//刪除具體代碼}//hashmap中維護一個紅黑樹結點靜態內部類,里邊有著一系列處理紅黑樹的方法static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {TreeNode<K,V> parent; TreeNode<K,V> left;TreeNode<K,V> right;TreeNode<K,V> prev; boolean red;TreeNode(int hash, K key, V val, Node<K,V> next) {super(hash, key, val, next);}}}

????? 再說一下Hashtable,它的實現和HashMap基本相同,但是在功能上也存在幾點不同,分析如下:

//繼承了Dictionary public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable {//private transient Entry<?,?>[] table;//鍵值對個數private transient int count;//閾值private int threshold;//加載因子private float loadFactor;//修改次數private transient int modCount = 0;private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//-------------------------------構造方法 ------------------------------// public Hashtable(int initialCapacity, float loadFactor) {if (initialCapacity < 0)throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);if (loadFactor <= 0 || Float.isNaN(loadFactor))throw new IllegalArgumentException("Illegal Load: "+loadFactor);if (initialCapacity==0)initialCapacity = 1;this.loadFactor = loadFactor;table = new Entry<?,?>[initialCapacity];threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);}public Hashtable(int initialCapacity) {this(initialCapacity, 0.75f);}public Hashtable() {this(11, 0.75f);}//-------------------------------功能方法 ------------------------------// //返回Enumeration集合,HashMap中是沒有的public synchronized Enumeration<K> keys() {return this.<K>getEnumeration(KEYS);}//HashMap中沒有這個方法public synchronized boolean contains(Object value) {if (value == null) {throw new NullPointerException();}Entry<?,?> tab[] = table;for (int i = tab.length ; i-- > 0 ;) {for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) {if (e.value.equals(value)) {return true;}}}return false;}//-------------------------------獲取方法 ------------------------------// //synchronized修飾,方法實線程同步的public synchronized V get(Object key) {Entry<?,?> tab[] = table;//獲取下標的方式不同,直接使用hash值進行下標獲取int hash = key.hashCode();int index = (hash & 0x7FFFFFFF) % tab.length;for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {if ((e.hash == hash) && e.key.equals(key)) {return (V)e.value;}}return null;}//-------------------------------添加方法 ------------------------------// public synchronized V put(K key, V value) {//value不可以為空,HashMap中就可以if (value == null) {throw new NullPointerException();}//判斷是否已經存在此key對應的鍵值對//如果存在則替換Entry<?,?> tab[] = table;int hash = key.hashCode();int index = (hash & 0x7FFFFFFF) % tab.length;@SuppressWarnings("unchecked")Entry<K,V> entry = (Entry<K,V>)tab[index];for(; entry != null ; entry = entry.next) {if ((entry.hash == hash) && entry.key.equals(key)) {V old = entry.value;entry.value = value;return old;}}//不存在則添加addEntry(hash, key, value, index);return null;}//具體添加方法private void addEntry(int hash, K key, V value, int index) {modCount++;Entry<?,?> tab[] = table;if (count >= threshold) {//如果哈希表中的鍵值對數量大于閾值,則擴容rehash();tab = table;hash = key.hashCode();index = (hash & 0x7FFFFFFF) % tab.length;}//添加@SuppressWarnings("unchecked")Entry<K,V> e = (Entry<K,V>) tab[index];tab[index] = new Entry<>(hash, key, value, e);count++;}//擴容操作@SuppressWarnings("unchecked")protected void rehash() {int oldCapacity = table.length;Entry<?,?>[] oldMap = table;// 擴容成一倍+1,HashMap是一倍int newCapacity = (oldCapacity << 1) + 1;if (newCapacity - MAX_ARRAY_SIZE > 0) {if (oldCapacity == MAX_ARRAY_SIZE)return;newCapacity = MAX_ARRAY_SIZE;}Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];modCount++;threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);table = newMap;for (int i = oldCapacity ; i-- > 0 ;) {for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {Entry<K,V> e = old;old = old.next;int index = (e.hash & 0x7FFFFFFF) % newCapacity;e.next = (Entry<K,V>)newMap[index];newMap[index] = e;}}}//Hashtable中不會牽扯到紅黑樹的操作 }

???? 說一下TreeMap,它依賴于紅黑樹實現,添加的元素是可以按著關鍵字排序的,排序規則可以自定義,分析如下:

public interface SortedMap<K,V> extends Map<K,V> {}public interface NavigableMap<K,V> extends SortedMap<K,V> {}//基于紅黑樹的實現 //紅黑樹:是一種大致平衡的平衡二叉樹,根節點和葉子節點是黑色,其他節點是黑色或者紅色, //每個紅色節點的兩個子節點是黑色,從每個葉子到根的所有路徑上不能有兩個連續的紅色節點 //從任意一節點到其每個葉子節點的所有路徑都包含相同數目的黑色節點 public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, java.io.Serializable {//比較器,用于維護樹中元素的順序private final Comparator<? super K> comparator;//樹private transient Entry<K,V> root;//節點個數private transient int size = 0;//修改次數private transient int modCount = 0;//------------------------------構造函數--------------------// public TreeMap() {comparator = null;}//自定義構造器初始化TreeMappublic TreeMap(Comparator<? super K> comparator) {this.comparator = comparator;}//根據現有的TreeMap構建一個TreeMap實例public TreeMap(SortedMap<K, ? extends V> m) {comparator = m.comparator();try {buildFromSorted(m.size(), m.entrySet().iterator(), null, null);} catch (java.io.IOException cannotHappen) {} catch (ClassNotFoundException cannotHappen) {}}//樹中所含元素個數public int size() {return size;}//------------------------------ 添加元素 --------------------// //添加元素public V put(K key, V value) {Entry<K,V> t = root;//初始化根節點if (t == null) {compare(key, key); root = new Entry<>(key, value, null);size = 1;modCount++;return null;}//如果已經有數據了int cmp;Entry<K,V> parent;//獲取到比較器Comparator<? super K> cpr = comparator;if (cpr != null) {//如果比較器不為空,按著比較器規則比較do {parent = t;cmp = cpr.compare(key, t.key);if (cmp < 0)//如果cmp<0,繼續比較左子樹t = t.left;else if (cmp > 0)//如果cmp>0,繼續比較右子樹t = t.right;elsereturn t.setValue(value);//值相同,直接覆蓋} while (t != null);} else {//沒有比較器,默認比較器比較if (key == null)throw new NullPointerException();@SuppressWarnings("unchecked")Comparable<? super K> k = (Comparable<? super K>) key;do {parent = t;cmp = k.compareTo(t.key);if (cmp < 0)t = t.left;else if (cmp > 0)t = t.right;elsereturn t.setValue(value);} while (t != null);}//添加節點Entry<K,V> e = new Entry<>(key, value, parent);if (cmp < 0)parent.left = e;elseparent.right = e;fixAfterInsertion(e);size++;modCount++;return null;}//------------------------------ 獲取元素 --------------------////根據key獲取valuepublic V get(Object key) {Entry<K,V> p = getEntry(key);return (p==null ? null : p.value);}//獲取值的具體操作final Entry<K,V> getEntry(Object key) {if (comparator != null)return getEntryUsingComparator(key);if (key == null)throw new NullPointerException();//根據默認的比較器查找對應key的value值Comparable<? super K> k = (Comparable<? super K>) key;Entry<K,V> p = root;while (p != null) {int cmp = k.compareTo(p.key);if (cmp < 0)p = p.left;else if (cmp > 0)p = p.right;elsereturn p;}return null;}//根據自定義比較器查找key對應的value值final Entry<K,V> getEntryUsingComparator(Object key) {K k = (K) key;Comparator<? super K> cpr = comparator;if (cpr != null) {Entry<K,V> p = root;while (p != null) {int cmp = cpr.compare(k, p.key);if (cmp < 0)p = p.left;else if (cmp > 0)p = p.right;elsereturn p;}}return null;}//------------------------------ 移除元素 --------------------////根據key獲取到節點,然后返回對應值,刪除節點public V remove(Object key) {Entry<K,V> p = getEntry(key);if (p == null)return null;V oldValue = p.value;deleteEntry(p);return oldValue;}//刪除的具體操作private void deleteEntry(Entry<K,V> p) {modCount++;size--;//如果被刪除的節點有左右子結點if (p.left != null && p.right != null) {Entry<K,V> s = successor(p);p.key = s.key;p.value = s.value;p = s;}Entry<K,V> replacement = (p.left != null ? p.left : p.right);if (replacement != null) {replacement.parent = p.parent;if (p.parent == null)root = replacement;else if (p == p.parent.left)p.parent.left = replacement;elsep.parent.right = replacement;p.left = p.right = p.parent = null;if (p.color == BLACK)fixAfterDeletion(replacement);} else if (p.parent == null) { //刪除唯一的節點root = null;} else { // 刪除的節點沒有子節點,直接刪除即可if (p.color == BLACK)fixAfterDeletion(p);if (p.parent != null) {if (p == p.parent.left)p.parent.left = null;else if (p == p.parent.right)p.parent.right = null;p.parent = null;}}}//刪除一個節點,依次移動節點,以保證平衡static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {if (t == null)return null;else if (t.right != null) {Entry<K,V> p = t.right;while (p.left != null)p = p.left;return p;} else {Entry<K,V> p = t.parent;Entry<K,V> ch = t;while (p != null && ch == p.right) {ch = p;p = p.parent;}return p;}}//還有一些其他的不同于HahhMap的方法,在這里不做介紹 }

最后說一下LinkedHashMap,它繼承自HashMap,它將集合中的元素使用一個雙向鏈表進行連接,在存取上是有序的,LinkedHashMap可以看成是使用HashMap進行存儲元素+鏈表鏈接元素保證順序,分析如下:

public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> {//每一個結點添加before、after屬性,用來記錄存取順序static class Entry<K,V> extends HashMap.Node<K,V> {Entry<K,V> before, after;Entry(int hash, K key, V value, Node<K,V> next) {super(hash, key, value, next);}}//雙向鏈表的頭結點transient LinkedHashMap.Entry<K,V> head;//雙向鏈表的尾節點transient LinkedHashMap.Entry<K,V> tail;//以什么順序進行鏈接,//accessOrder為true時按訪問順序//accessOrder為false時按插入順序,默認final boolean accessOrder;//---------------------------構造函數----------------------////使用父類構造方法public LinkedHashMap(int initialCapacity, float loadFactor) {super(initialCapacity, loadFactor);accessOrder = false;//默認按插入順序}public LinkedHashMap(int initialCapacity) {super(initialCapacity);accessOrder = false;//}public LinkedHashMap() {super();accessOrder = false;}public LinkedHashMap(Map<? extends K, ? extends V> m) {super();accessOrder = false;putMapEntries(m, false);}//---------------------------功能函數----------------------////---------------------------添加方法----------------------////用的時HashMap中的put方法public V put(K key, V value) {return putVal(hash(key), key, value, false, true);}//具體添加,onlyIfAbsent,evict這兩個參數發揮作用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;if ((p = tab[i = (n - 1) & hash]) == null)tab[i] =newNode (hash, key, value, null);else {Node<K,V> e; K k;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);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 1sttreeifyBin(tab, hash);break;}if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}if (e != null) {V oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e);//按訪問順序return oldValue;}}++modCount;if (++size > threshold)resize();afterNodeInsertion(evict);return null;}//按訪問順序鏈接,將結點鏈接到最后void afterNodeAccess(Node<K,V> e) {LinkedHashMap.Entry<K,V> last;if (accessOrder && (last = tail) != e) {LinkedHashMap.Entry<K,V> p = (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;p.after = null;if (b == null)head = a;elseb.after = a;if (a != null)a.before = b;elselast = b;if (last == null)head = p;else {p.before = last;last.after = p;}tail = p;++modCount;}}//LinkedHashMap就是用一個雙向鏈表將HashMap中的元素鏈接起來保證有序,這里只說一個保持順序的方法 }

以上是對Map集合做一下簡單介紹。

總結

以上是生活随笔為你收集整理的16、java中的集合(3)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。