Java集合初體驗(謹個人學習記錄)
概述
Java 集合可分為 Collection 和 Map 兩種體系
- Collection 介面 :單列資料 。定義了存取一組物件的方法的集合
- Lits :有序列表 ,可重複的集合
- Map :無序列表 ,不可重複的集合
- Map 介面 :雙列資料 。儲存具有對映關係 “key” :“value” 鍵值對 的集合
Collection 介面繼承樹
Map 介面繼承樹
{name:"張三"} >> 鍵值對
Collection 介面方法
介面方法 | 作用 |
---|---|
add(Object obj) addAll(Collection coll) |
新增元素 |
int size() | 獲取有效元素的個數 |
void clear() | 情況集合 |
boolean isEmpty() | 是否是空集合 |
boolean contains(Object obj) | 是否包含某個元素 ,通過 equals() 判斷是否為同一個物件 |
boolean containsAll(Collection coll) | 是否包含某個元素 ,拿兩個集合的元素挨個比較 |
boolean remove(object obj) | 刪除元素 ,刪除第一個匹配的元素 |
boolean retainAll(Collection c) | 取兩個集合的交集 |
Object[] toArray() | 轉成物件陣列 |
iterator() | 迭代器物件 ,集合遍歷 |
Collection 子介面之一 :List介面 概述
- 使用 List 替代 陣列 。
- 元素有序 且 元素可以重複
- 每個元素對應一個索引值
- 常用實現類 :ArrayList 、LinkedList 、Vector [執行緒安全]
ArrayList 原始碼分析 【底層使用 陣列儲存 】查詢快 ,使用索引值查 [執行緒不安全 ]
jdk 1.7 :
構造器初始化的時候.就建立一個 長度為 10 的陣列容量 Object[] elemrntData;
jdk 1.8 :
構造器初始化的時候並不會建立陣列長度 ,而是在第一次 呼叫 list.add(); 方法的時候,才去建立陣列長度為 10
後續操作與 jdk 1.7 無異
LinkedList 原始碼分析 【底層使用 雙向連結串列儲存】 增刪快 ,[執行緒不安全 ]
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;
}
}
List 介面方法
介面方法 | 作用 |
---|---|
void add(int index, Object ele); | 在 index 索引位置插入 元素 ele |
boolean addAll(int index, Collection eles); | 從 index 索引位置開始將集合 eles 中的所有元素新增進來 |
Object get(int index); | 獲取指定 index 索引值位置的元素 |
int indexOf(Object obj); | 返回元素 obj 在集合中首次出現的位置 |
int lastIndexOf(Object obj); | 返回元素 obj在當前集合中最後一次出現的的位置 |
Object remove(int index); | 移除指定 index索引值位置的元素 ,並返回此元素 |
Object set(int index, Object ele); | 設定指定 index索引值位置的元素為 ele |
List subList(int fromIndex, int toIndex); | 返回從 fromIndex 到 toIndex 索引值位置的子集合 。 |
**總結 :List 常用方法 **
增 :add(Object obj); / add(int index, Object obj);
刪 :remove(int index); / remove(Object obj);
改 :set(int index, Object ele);
查 :get(int index);
長度 :size();
遍歷 :
① 、迭代器 Iterator
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next);
}
②、forEach
for (Object obj : list) {
System.out.println(obj);
}
③、for 迴圈
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
Collection 子介面之二 :Set 介面
簡介 :
- Set 介面是Collection的子介面 ,Set 介面沒有提供額外的方法
- Set 集合不允許包含相同的元素 ,否則會新增操作失敗
- Set b判斷兩個物件是否相同 根據 equals() 方法 。而不是根據 “==” 運算子 。
常用實現類之一 :HashSet
HashSet 底層 :陣列 + 連結串列 的結構
-
HashSet 按照 Hash 演算法來儲存集合中的元素 ,具有很好的 存取 、查詢 、刪除 效能 。
-
特點 :
- 無序列表
無序性 :不等於隨機性 。
是指 儲存的資料在底層陣列中並非按照陣列索引的順序新增 ,而是根據資料的雜湊值確定儲存位置
- 不是執行緒安全
- 元素可以為
null
-
HashSet 集合判斷兩個個元素相等的標準
- 兩個物件通過 hashCode() 方法比較相等 。並且兩個物件的 equals() 方法返回值相等 。
-
存放在 Set 容器中的物件 ,必須重寫 equals() 方法和 hashCode(Object obj); 方法
-
不可重複性 :
是指 保證新增的元素按照 equals() 判斷時 ,不能返回 true . 即:相同的元素只能新增一個 。
-
新增元素的過程 :以HashSet 為例 :
向HashSet 中新增元素a ,首先呼叫元素a所在類的hashCode() 方法 ,計算元素a的雜湊值 ,
此雜湊值接著通過某個演算法計算出在 HashSet 底層陣列中的存放位置 (索引位置),判斷
陣列對應索引位置是否已經有元素 :
情況一 :
如果此位置上沒有其他元素 ,則元素a新增成功 。
情況二 :
如果此位置上有其他元素b(或以連結串列形式存在的多個元素),則比較元素a與元素b的hash值 :
如果hash值不相同 ,則元素a新增成功 。
情況三 :
如果hash值相同 ,進而需要呼叫元素a所在類的equals() 方法 :
equals() 返回 true ,元素 a 新增失敗 。
equals() 返回 false ,則元素 a 新增成功 。
Set 實現類之三 :LinkedHashSet
- LinkedHashSet 根據元素的 hashCode 值來決定元素的儲存位置 。但它同時使用雙向連結串列維護元素的次序 。
- LinkedHashSet 插入效能略低 HashSet ,但在 迭代器訪問 Set 裡的全部元素時有很好的效能 。
- 不允許集合元素重複 。
Set 實現類之三 :TreeSet
- TreeSet 是 SortedSet 介面的實現類 。TreeSet 可以確保元素處於排序狀態 。
- TreeSet 底層使用
紅黑樹
資料結構儲存資料 。 - TreeSet 兩種排序方法 :自然排序 和 定製排序 。預設情況下 TreeSet 採用自然排序
instanceof 嚴格來說是Java中的一個雙目運算子,用來測試一個物件是否為一個類的例項
1、向 TreeSet 中新增資料 ,要求必須是相同類的物件 ,例如 :要麼就都是整型 ,要麼都是字串 ,不能參半
2、兩種排序方式 :自然排序(實現 Comparable 介面) 和 定製排序(Comparator)
3、自然排序中 ,比較兩個物件是否相同的標準 :comparmTo() 返回0
1、自然排序
public class User implements Comparable {
private Integer age;
// ... 省略set get
@Override
public int compareTo(Object o) {
if (o instanceof User) {
User user = (User) o;
return this.age.compareTo(user.age);
} else {
throw new RuntimeException("型別不匹配 ");
}
}
/*
Set seen = new TreeSet();
seen.add(new User(12));
seen.add(new User(123));
seen.add(new User(456));
*/
2、定製排序
Comparator comparator = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof User && o2 instanceof User) {
User u1 = (User) o1;
User u2 = (User) o2;
return Integer.compare(u1.getAge(), u2.getAge()); // 從小到大
// return Integer.compare(u1.getAge(), u2.getAge()); 從大到小
} else {
throw new RuntimeException("型別不匹配 ");
}
}
};
Set seen = new TreeSet(comparator);
seen.add(new User(12));
seen.add(new User(123));
seen.add(new User(456));
Map :介面
簡介 :
HashMap [主要實現類],執行緒不安全,可以儲存nul鍵值對
- key :無序的,不可用重複 ,使用 Set 儲存所有的 keu ,儲存類物件 需要 重寫類的 hashCode 和 equals
- value :無序的,可重複的 ,使用 Collection 儲存 value 。儲存類物件需要重寫 equals
- 一個鍵值對key:value 構成一個 Entry 物件 entry無序的,不可重複讀, 使用 Set 儲存entry 。
LinkedHashMap [對於頻繁的遍歷] ,效率高於HashMap
TreeMap [排序 使用 key作為排序條件]
Hashtable [執行緒安全,效率低] jdk1.0 ,目前不推薦使用 。
面試題
HashMap 的底層 :在jdk7及以前 是 陣列 + 連結串列 結構
在 jdk1.8 是 陣列+連結串列+紅黑樹 結構
HashMap的底層實現原理 ?以 jdk 1.7 為例
HashMap map = new HashMap();
在例項化以後 ,底層建立了長度為 16 的一維陣列 Entry[] table.
map.put(key1,value1);
首先,呼叫 key1 所在類的hashCode() 計算 key1 的雜湊值 ,此雜湊值經過演算法計算後,得到在Entry陣列中的存放位置 。
如果此位置上的資料為空 ,此時的 key1-value1 新增成功 --- 情況 1
如果此位置上的資料不為空 ,(此位置已存在資料 ,),比較 key1 和已經存在的資料的雜湊值 :
如果 key1 的雜湊值與已經存在的資料的雜湊值不相同 ,此時 key1-value1 新增成功 --- 情況 2
如果 key1 的雜湊值和已經存在的某一個數據(key2-value2)的雜湊值相同 ,則繼續比較 :呼叫 key1 所在類的equals(key2)方法 ,比較 :
如果equals() 返回 false ,此時 key1-value1 新增成功 --- 情況 3
如果 equals() 返回true ,使用 value1 替換 value2 .
擴容問題 :擴容為 原來的兩倍 。
補充 :關於情況2和情況3 :此時 key1-value1 和原來的資料以連結串列的形式儲存
介面方法 | 作用 |
---|---|
新增、刪除、修改操作 | |
Object put(Object key, Object value) | 將指定key-value新增(修改)到當前map物件中 |
void putAll(Map m) | 將 Map m 中的所有key-value鍵值對存放到當前map中 |
Object remove(Object key) | 移除指定 key 的 key-value鍵值對 ,並返回 value |
void clear() | 清空當前 map 中的所有資料 |
元素查詢操作 | |
Object get(Object key) | 獲取指定 key 對應的 value |
boolean containsKey(Object key) | 是否包含指定的 key |
boolean containsValue(Object value) | 是否包含指定的 value |
int size() | 返回 map 中 key-value 鍵值對的個數 |
boolean isEmpty() | 判斷當前 map 是否為空 |
boolead equals(Object obj) | 判斷當前 map 和引數對 obj 是否相等 |
元檢視操作 | |
Set keySet() | 返回所有 key 構成的 Set 集合 |
Collection values() | 返回所有的 value 構成的 Collection 集合 |
Set entrySet() | 返回 所有 key-value 鍵值對 構成的 Set 集合 |
面試題
談談你對 HashMap 中 put/get方法的認識 ?
再談談 HashMap 的擴容機制 ?預設大小是多少?什麼是負載因子(或填充比)
什麼是吞吐臨界值 (或閥值 、threshold)
HashMap 原始碼中的常量
Map 原始碼分析 :jdk 1.8 (未完)
簡要說明
jdk 1.8 初始化容量 是在 第一次 put 的時候 對陣列進行初始化 。
jdk 1.7 是在構造器初始化容量大小 .
1.8 HashMap 結構圖
- 一 :JDK 1.8 中 涉及的 資料結構
1、位桶陣列 (定義儲存資料的陣列) 【陣列 】
transient Node<K,V>[] table; // 鍵值對 <k,v>
2、陣列元素 Node<k,v> ,實現類 Entry 介面 【連結串列 】
Node 是單向連結串列,Node<k,v>是一個內部類 ,相當於是 一個 節點類
static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next; // 構造器 Hash值 ,鍵 ,值 ,下一個節點 (當前節點的下一個節點引用 。) 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; } // 判斷兩個 Node 是否相等 ,若 key 和 value 都相等 ,返回true 。可以與自身比較為true / 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; } }
3、紅黑樹 【樹結構】
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; // needed to unlink next upon deletion boolean red; // 樹節點顏色屬性 TreeNode(int hash, K key, V val, Node<K,V> next) { super(hash, key, val, next); } /** * Returns root of tree containing this node. */ // 返回當前節點的 根節點 。 final TreeNode<K,V> root() { for (TreeNode<K,V> r = this, p;;) { if ((p = r.parent) == null) return r; r = p; } }
- 二 : 構造器
// 1、初始化時 指定初始容量和負載因子 .如果指定的(初始容量為負數或者負載因子非正).丟擲異常 IllegalArgumentException 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; this.threshold = tableSizeFor(initialCapacity); } // 2、指定初始容量 使用預設的負載因子 0.75f public HashMap(int initialCapacity) { // 呼叫的還是 兩個引數的構造器 this(initialCapacity, DEFAULT_LOAD_FACTOR); } // 3、沒有引數 ,預設初始容量 16 ,預設負載因子 0.75f public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted } // 4、用 m 的元素初始化雜湊對映 public HashMap(Map<? extends K, ? extends V> m) { this.loadFactor = DEFAULT_LOAD_FACTOR; putMapEntries(m, false); }
- 三 : HashMap 的存取機制
1、get(Object key); 如何 getValue 值 【獲取指定 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; // Entry 物件陣列 Node<K,V> first, e; // 在 tab 陣列中經過雜湊的第一個位置 int n; K k; // 找到插入的第一個 Node節點 ,方法是 hash值和 n-1 相與 ,tab[(n - 1) & hash]) // 在一條鏈上的hash值是相同的 if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) { // 檢查第一個 Node節點 是不是要找的 Node if (first.hash == hash && // always check first node // 判斷條件是 hash值要相同 ,並且 key值相同 ((k = first.key) == key || (key != null && key.equals(k)))) return first; // 檢查 first 後面的 Node if ((e = first.next) != null) { if (first instanceof TreeNode) // 如果是樹節點的一個例項 ,則呼叫樹的方法 查詢目標節點 return ((TreeNode<K,V>)first).getTreeNode(hash, key); /*遍歷連結串列.找到 key值和 hash值 都相等的 Node*/ do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } while ((e = e.next) != null); } } // 沒有返回 null return null; }
get(key) 方法時獲取 key 的 hash值 ,計算 hash&(n-1) 得到在連結串列陣列中的儲存位置 [ first=tab[hash&(n-1)] ] ,
先判斷 first 的 key 是否等於引數 key ,不等就遍歷後面的連結串列找到相同的 key值 返回對應的 value值即可 .
**2、put(key, value); ** 【將指定key-value新增(修改)到當前map物件中】
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; // 位桶初始化 預設容量 16 // 如果 tab在((n-1)&hash)的值是空 ,就新建一個節點插入到該位置 if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); /*表示有衝突,開始處理衝突*/ else { Node<K,V> e; K k; // 檢查第一個Node, P是不是要找的值 if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) // 如果p 已經是樹節點的一個例項 ,即這裡已經是樹結構了 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); else { // p與新節點既不完全相同 ,也不是 TreeNode 例項 .普通節點 for (int binCount = 0; ; ++binCount) { /*指標為空,就掛在後面 */ if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); // 指向 新節點 ,將新節點插入到連結串列尾部 /*如果衝突的個數已經達到8個 ,判斷是否需要改變衝突的儲存結構 treeifyBin 首先判斷當前的 HashMap 長度 ,如果個數不足64,只進行擴容 resize(),擴容tab,如果個數達到64,將衝突的儲存結構變為紅黑樹 . */ if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } /*如果有相同的 key值就結束遍歷 .*/ if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; // 相當於 pNode = pNode.next ,迴圈變數 } } /*如果連結串列上有相同的 key值 新的value 替換(覆蓋) 舊的value*/ if (e != null) { // existing mapping for key 鍵的現有對映 ,鍵的 value 存在 V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); // 用於 LinkedHashMap return oldValue; // 返回存在的 value值 } } ++modCount; /*如果當前大小大於門限 ,門限是初始容量的0.75倍*/ if (++size > threshold) resize(); // 擴容兩倍 afterNodeInsertion(evict); // 用於 LinkedHashMap return null; }
1、判斷鍵值對陣列 tab[] 是否為空或為null ,否則以預設大小 resize() ;
if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length;
2、根據鍵值 key 計算hash值 得到插入的陣列索引 i ,如果 tab[i] == null ,直接新建節點新增 . 不為null 轉入第三步
if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null);
3、判斷當前陣列中處理 hash 衝突的方式是連結串列還是紅黑樹(check 第一個節點型別即可),分別處理 .
- 四 :resize() 擴容機制
構造 hash 表時,如果不指定初始大小 ,預設容量大小是 16 (Node 陣列大小16) ,如果Node[] 陣列中的元素達到(填充比 * Node.length) , 則重新調整 HashMap 大小 變為原來的兩倍大小 ,【擴容很耗時!】
final Node<K,V>[] resize() { Node<K,V>[] oldTab = table; int oldCap = (oldTab == null) ? 0 : oldTab.length; // 第一次put oldCap=0 int oldThr = threshold; // 當前臨界值 threshold=0 賦值給 oldThr int newCap, newThr = 0; // 如果舊錶的長度不為空 if (oldCap > 0) { // 第一次put 不進去 if (oldCap >= MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return oldTab; } /*把新表的長度設定為舊錶長度的兩倍 ,newCap=2*oldCap */ else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY) /*把新表的門限設定為舊錶門限的兩倍 ,newThr = 2*oldThr */ newThr = oldThr << 1; // double threshold } /*如果舊錶的的長度是0,說明是第一次初始化表*/ else if (oldThr > 0) // initial capacity was placed in threshold // 第一次put 不進去 newCap = oldThr; else { // zero initial threshold signifies using defaults // 第一次put 進去 newCap = DEFAULT_INITIAL_CAPACITY; // 將預設容量16 賦值給 newCap newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);// newThr=(預設容量*載入因子)=12 } if (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]; // new Node ,陣列出現容量是16 newCap=16 , table = newTab; // 把新表賦值給 table /*如果舊錶不為空 ,把舊錶中的資料移動到新表中 */ 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) // 說明舊錶這個Node 沒有連結串列 ,直接存放在新表的 e.hash & (newCap - 1)位置 . newTab[e.hash & (newCap - 1)] = e; else if (e instanceof TreeNode) // e 是 樹結構的例項 ,則進行紅黑樹的重hash分佈 ((TreeNode<K,V>)e).split(this, newTab, j, oldCap); /*如果e後面有連結串列,表示e後面鏈著單鏈表 ,需要遍歷連結串列 .將每個節點重新計算在新表的位置,並進行搬運 .*/ else { // preserve order 保證順序 Node<K,V> loHead = null, loTail = null; Node<K,V> hiHead = null, hiTail = null; Node<K,V> next; do { next = e.next; // 記錄下一個節點 /*新表是舊錶的兩倍容量 ,實際上把連結串列分為兩隊 , e.hash & oldCap偶數一對 , e.hash & oldCap奇數一對 */ if ((e.hash & oldCap) == 0) { if (loTail == null) loHead = e; else loTail.next = e; loTail = e; } else { if (hiTail == null) hiHead = e; else hiTail.next = e; hiTail = e; } } while ((e = next) != null); if (loTail != null) { //lo隊不為null ,放在新表原位置 loTail.next = null; newTab[j] = loHead; } if (hiTail != null) { //hi隊不為null ,放在新表 j + oldCap 位置 hiTail.next = null; newTab[j + oldCap] = hiHead; } } } } } return newTab; // 返回新表 }
- 五 :JDK1.8 使用紅黑樹的改進
在 jdk 1.7 中 ,HashMap 結構為 陣列+連結串列 。
在 jdk 1.8 中 ,HashMap 處理 “碰撞” 情況增加了 紅黑樹這種資料結構 ,當碰撞節點較少,採用連結串列儲存 ,當 閥值 > 8 時 ,
並且 陣列個數達到 64 ,則採用紅黑樹 (特點 : 查詢時間是 O(logn)),儲存 ,將連結串列儲存轉換成紅黑樹儲存 。
最壞的情況即 所有的key 都對映到同一個 位桶(陣列索引位置)中 ,HashMap就退化成一個連結串列 ,查詢時間從O(1) 到 O(n)
升級為 紅黑樹(也是一個二叉樹)
使用 hash值 作為樹的分支變數 ,如果兩個 hash 值不相等 ,但指向同一個陣列索引 ,hash 值 較大的會插入右子樹 。
如果 hash 值相等 ,key 值 最好實現了Comparable ,可以按順序插入 (自然排序 、定製排序 ) .
遍歷方式 :
// 第一種 此方式可以同時取出 key value 的值
Iterator<Map.Entry<String,Integer>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Integer> next = iterator.next();
System.out.println(next.getKey() + next.getValue());
}
// 第二種 先取出 key 的值 ,然後通過get(key)方法 獲取value 效率較低
Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
String next = iterator.next();
System.out.println(next + map.get(next));
}
LinkedHashMap (瞭解)
簡介 :
LinkedHashMap 是 HashMap 的子類 ,內部也是呼叫父類的 put 方法 ,只是 建立Node 節點的時候 ,呼叫 LinkedHashMap 本身的 newNode()方法
// LinkedHashMap 部分原始碼
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);
}
}
TreeMap (瞭解)
簡介 :
向 TreeMap 中新增 key-value ,要求 key 必須由同一個類建立的物件 。
因為要按照 key 進行排序 :自然排序 、定製排序 。(也只能說 key 排序 ,value排序無效 )
Properties 處理屬性檔案
Properties 是 Hashtable 的子類
Properties pros = new Properties();
FileInputStream fs = new FileInputStream("類路徑下的 properties字尾檔案 ");
pros.load(fs); // 載入流對應的檔案
String name = pros.getProperties("key");
String age = pros.getProperties("value");