Java集合 Map 集合 與 操作集合的工具類: Collections 的詳細說明

每博一文案
別把人生,輸給心情
師父說:心情不是人生的全部,卻能左右人生的全部,
你有沒有體會到,當你心情好的時候,生活仿佛陽光燦爛,順風順水,
當你心情不好的時候,似乎周圍的一切都糟糕透了,
有時候,我們不是輸給了別人,而是敗給了壞心情的自己,
人活著就像一個陀螺,為了生活不停的轉動,永遠都有忙不完的事,
有時候又像沙漠中的駱駝,背負著重擔努力地前行,卻不知道哪里才是終點,
先現在情緒低落,只是因為陷進了自我糾纏的陷阱,等到熬過了這段苦難,
你會發現你所糾結的東西,真的只是無關痛癢的小事,
生活就像天氣,不會總是晴天,也不會一直陰雨,喜歡和討厭是次要的,關鍵是你要學會調整自己,
心靜了,才能聽見自己的心聲,心清了,才能照見萬物的本性,
假如任由壞情緒累積和蔓延,很多事只會變得越來越糟糕,
既然做不到讓所有人都滿意,為何不努力讓自己開心?
生活是你自己的,喜怒悲歡都由你自己決定,記得別被壞情緒束縛住,
不要讓你的人生,輸給了心情,
—————— 一禪心靈廟語
目錄- Java集合 Map 集合 與 操作集合的工具類: Collections 的詳細說明
- 每博一文案
- 1. Map介面概述
- 2. Map介面:常用方法
- 3. Map實作類之一:HashMap
- 3.1 HashMap的存盤結構
- 3.2 HashMap原始碼中的重要常量
- 3.3 HashMap的存盤結構:JDK 1.8之前 / JDK 1.8之后
- 3.3.1 JDk 1.8 之前
- 3.3.2 JDk 1.8 及之后
- 3.3.3 JDK8 HashMap 集合添加元素的程序
- 3.3.4 JDK8 HashMap 進行 "擴容"和 "樹形化"
- 3.3.5 總結:JDK1.8 相較于之前的變化:
- 4. Map實作類之二:LinkedHashMap
- 5. Map實作類之三:TreeMap
- 6. Map實作類之四:Hashtable
- 7. Map實作類之五:Properties
- 8. Map 介面下的集合遍歷方式
- 9. Collections工具類
- 9.1 Collections常用方法
- 10. 總結:
- 11. 最后:
1. Map介面概述




-
Map 介面與 Collection 并列存在的,用于保存具有映射關系的資料:key-value 被稱為 鍵值對 ,
-
Java集合可分為 Collection 和 Map 兩種體系,
- Collection 介面:單例資料,定義了存取一組物件的方法的集合,
- List : 元素有序,可重復的集合,
- Set :元素無序,不可重復的集合,
- Map 介面:雙列資料,保存具有映射關系”key-value對“ 的集合,
- Collection 介面:單例資料,定義了存取一組物件的方法的集合,
-
Map 中的 key 和 value 都可以是任何參考型別的資料,
- key 和 value 都是參考資料型別,都是存盤物件的記憶體地址的,不是基本資料型別,
- 其中 key 起到主導地位,value 是 key 的一個附屬品,
-
Map 中的 key 用 Set 集合存盤的,不允許重復,即同一個 Map 物件所對應的類,必須重寫hashCode() 和 equals() 方法,但是其中的 value 值是可以存盤重復的資料的,而 value 值則是被 Collection 介面集合存盤的,
-
常用 String 類作為 Map 的 ”鍵“,
-
key 和 value 之間存在單向一對一關系,即通過指定的 key 總能找到唯一的,確定的 value ,
-
Map 介面的常用實作類:
- HashMap 作為Map的主要實作類,執行緒不安全的,效率高,可以存盤 null 的key 和 value,HashMap是 Map 介面使用頻率最高的實作類
- LinkedHashMap 保證再遍歷Map元素時,可以按照添加的順序實作遍歷,原因: 在原有的HashMap底層結構基礎上,添加了一對指標,指向前一個和后一個元素,對于頻繁的遍歷操作,此類執行效率高于HashMap
- TreeMap 保證按照添加的 key-value鍵值對進行排序,實作排序遍歷.此時考慮key的自然排序或定制排序,底層使用紅黑樹:
- Hashtalbe 作為古老的實作類,執行緒安全的,效率低,不可以存盤 null
- Properties 主要用于組態檔的讀取,
-
鍵值對的示圖:

2. Map介面:常用方法
添加、洗掉、修改操作:
- put(K key, V value) : 將指定的 key 和 value 值添加/修改到該集合當中,
V put(K key,V value); // 將指定的 key 和 value 值添加/修改到該集合當中,
- putAll(Map m) : 將 m 中所有的key-value 值存放到當前 物件集合當中,
void putAll(Map<? extends K,? extends V> m); // 將m中的所有key-value對存放到當前map集合當中
- remove(Object key) : 移除指定key的key-value對,并回傳value,
V remove(Object key); // 移除指定key的key-value對,并回傳value
- clear() : 清空當前map中的所有資料,
void clear(); // 清空當前map中的所有資料
- size() : 回傳此集合中存盤的元素資料(鍵值對)的數量,
int size(); // 回傳此集合中存盤的元素資料(鍵值對)的數量,
舉例:
import java.util.HashMap;
import java.util.Map;
public class MapTest {
public static void main(String[] args) {
// Map 介面 , HashMap實作類,多型,<String,Integer> 泛型
Map<String,Integer> map = new HashMap<String,Integer>();
// 添加元素資料:
map.put("zhangsan",66);
map.put("lisi",89);
map.put("wangwu",97);
map.put("lihua",99);
System.out.println(map);
int size = map.size(); // 回傳該集合中存盤的鍵值對的數量,
System.out.println(size);
System.out.println("*********************");
Integer zhangsan = map.remove("zhangsan"); // 移除key = zhangsan的元素資料,并回傳該移除的value值,
System.out.println(zhangsan);
System.out.println(map);
map.clear(); // 清空該Map 集合當中的存盤的元素資料
System.out.println(map.size());
}
}

舉例
import java.util.HashMap;
import java.util.Map;
public class MapTest {
public static void main(String[] args) {
// Map 介面 , HashMap實作類,多型,<String,Integer> 泛型
Map<String,Integer> map = new HashMap<String,Integer>();
// 添加元素資料:
map.put("zhangsan",66);
map.put("lisi",89);
Map<String,Integer> map2 = new HashMap<String,Integer>();
map2.put("wangwu",97);
map2.put("lihua",99);
map.putAll(map2); // 將 map2 集合中所有的key-value鍵值對添加到此 map集合當中去
// 注意:兩者集合存盤的元素資料型別必須是一致的才可以添加成功,
System.out.println(map);
}
}

元素查詢的操作:
- get(Object key) : 獲取指定key對應的value,
V get(Object key); // 獲取指定key對應的value
- containsKey(Object key) : 判斷該集合當中是否包含指定的 key值,
boolean containsKey(Object key); // 判斷該集合當中是否包含指定的 key 值,
- containsValue(Object key) : 判斷該集合當中是否包含指定的 value 值,
boolean containsValue(Object value); // 判斷判斷該集合當中是否包含指定的 value 值,
- isEmpty() : 判斷此集合是否為 空,是回傳 true,不是回傳 false,
boolean isEmpty(); // 判斷此集合是否為 空,是回傳 true,不是回傳 false;
- equals(Object o) : 判斷當前map和引數物件 o 是否相等,
boolean equals(Object o); // 判斷當前map和引數物件 o 是否相等
舉例:
import java.util.HashMap;
import java.util.Map;
public class MapTest {
public static void main(String[] args) {
// Map 介面 , HashMap實作類,多型,<String,Integer> 泛型
Map<String,Integer> map = new HashMap<String,Integer>();
// 添加元素資料:
map.put("zhangsan",66);
map.put("lisi",89);
map.put("wangwu",97);
map.put("lihua",99);
System.out.println(map.get("zhangsan")); // 獲取到對應 key上的 value值
System.out.println(map.containsKey("zhangsan")); // 判斷該集合當中是否存在 key = zhangsan的鍵值對
System.out.println(map.containsValue(99)); // 判斷該集合當中是否存在 value = https://www.cnblogs.com/TheMagicalRainbowSea/archive/2023/02/03/99的鍵值對
System.out.println(map.isEmpty()); // 判斷該集合是否為空
System.out.println(map.equals(map)); // 判斷當前map和引數物件 o 是否相等
}
}

元視圖操作的方法:
- keySet() : 回傳所有key構成的Set集合,從該方法中可以看出 Map 介面下的集合中的 key 值是存盤在 Set 介面集合當中的,
Set<K> keySet(); // 回傳所有key構成的Set集合
- values() : 回傳所有value構成的Collection集合,從該方法中可以看出 Map 介面下的集合中的 value 值是存盤在 Collection 介面集合當中的,
Collection<V> values(); // 回傳所有value構成的Collection集合
舉例:
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapTest {
public static void main(String[] args) {
// Map 介面 , HashMap實作類,多型,<String,Integer> 泛型
Map<String,Integer> map = new HashMap<String,Integer>();
// 添加元素資料:
map.put("zhangsan",66);
map.put("lisi",89);
map.put("wangwu",97);
map.put("lihua",99);
Set<String> keys = map.keySet(); // 回傳此集合當中所有的 key 值存盤到 Set 集合當中
for (String s : keys) {
System.out.println(s);
}
System.out.println("****************");
Collection<Integer> values = map.values(); // 回傳此集合當中所有的 value 值存盤到 Collection 集合當中
// Collection 介面集合可以使用迭代器
Iterator<Integer> iterator = values.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}

- entrySet() : 回傳該集合當中的所有 key-value鍵值對,并存盤到 Set 集合當中后,再回傳一個 Set 集合物件(該集合存盤了所有的key-value) 值,
Set<Map.Entry<K,V>> entrySet(); // 回傳所有key-value對構成的Set集合
其中的 Map.Entry 表示的是一個介面,也可以理解為是一個類,
* Set<Map.Entry<K,V>> entrySet() 將 Map集合轉換成 Set集合
* 假設現在有一個 Map集合 ,如下所示:
* map1 集合物件
* key value
* 1 zhangsan
* 2 lisi
* 3 wangwu
* 4 zhaoliu
*
* Set set = mop1.entrySet();
* set 集合物件
* 1=zhangsan
* 2=lisi
* 3=wangwu
* 4=zhaoliu
Map.Entry<K,V> 的圖示:


舉例:
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapTest {
public static void main(String[] args) {
// Map 介面 , HashMap實作類,多型,<String,Integer> 泛型
Map<String,Integer> map = new HashMap<String,Integer>();
// 添加元素資料:
map.put("zhangsan",66);
map.put("lisi",89);
map.put("wangwu",97);
map.put("lihua",99);
Set<Map.Entry<String, Integer>> entries = map.entrySet();
Iterator<Map.Entry<String, Integer>> iterator = entries.iterator();
while(iterator.hasNext()) {
Map.Entry<String, Integer> entry = iterator.next();
// getKey()獲取 key 值,getValue()獲取value值
System.out.println(entry.getKey() + "--->" + entry.getValue());
}
}
}

3. Map實作類之一:HashMap



-
HashMap 是 Map 介面使用頻率最高的實作類,
-
HashMap 允許存盤 null 值,key 可以為 null ,但僅僅只能有一個,因為不可重復,value 可以為 null ,無序
-
HashMap 中所有的 key 構成的集合是存盤在 Set 當中的,無序的,不可重復的,所以:key 所在類和 Set 集合是一樣的必須重寫 euqlas() 和 hashCode() 方法,其中 Java當中的包裝類和String 類都重寫了 equals() 和 hashCode()方法,基本上只有我們自定的類需要重寫,
-
一個key-value 構成一個
Map.Entry, -
所有的 Map.Entry 構成的集合是 Set 無序的,不可重復的,
-
HashMap
判斷兩個 key 相等的標準是: 兩個key 通過 equals() 方法回傳 true , hashCode 值也相等, -
HashMap
判斷兩個 value 相等的標準是: 兩個 value 通過 equals() 方法回傳 true, -
HashMap 集合底層是哈希表的資料結構
- 哈希表是一個陣列 + 單向鏈表 的結合體,
- 陣列:在查詢方面效率很高,隨機增刪方面很低,
- 鏈表:在隨機增刪方面效率較高,在查詢方面效率低,
- 而哈希表:將以上兩種資料結構融合在一起,充分發揮它們各自的優點,
-
對于 HashMap 中的方法基本上都是繼承了對應的 Map 介面的方法,上面已經說明了,這里就不多介紹了,
舉例:
如下是 Set 中的 Key 存盤自定義類 Person5 ,其中并沒有重寫Object 中的 equals() 方法和 hashCode()方法,會出現 Key 存盤到重復的資料,
package blogs.blogs7;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class HashMapTest {
public static void main(String[] args) {
HashMap<Person5,Integer> hashMap = new HashMap<Person5, Integer>();
hashMap.put(new Person5("Tom",19),1);
hashMap.put(new Person5("Tom",19),1);
hashMap.put(new Person5("Tom",19),1);
hashMap.put(new Person5("zhangsan",23),4);
hashMap.put(new Person5("lihua",20),5);
// 遍歷HashMap 集合
Set<Map.Entry<Person5,Integer>> entries = hashMap.entrySet();
for (Map.Entry<Person5,Integer> entry : entries) {
System.out.println(entry);
}
}
}
class Person5 {
String name;
int age;
public Person5() {
}
public Person5(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person5{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

修改: 重寫其中的 Key 值的 Set 集合中存盤的 類中的 equals() 和 hashCode() 方法,
package blogs.blogs7;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
public class HashMapTest {
public static void main(String[] args) {
HashMap<Person5,Integer> hashMap = new HashMap<Person5, Integer>();
hashMap.put(new Person5("Tom",19),1);
hashMap.put(new Person5("Tom",19),1);
hashMap.put(new Person5("Tom",19),1);
hashMap.put(new Person5("zhangsan",23),4);
hashMap.put(new Person5("lihua",20),5);
// 遍歷HashMap 集合
Set<Map.Entry<Person5,Integer>> entries = hashMap.entrySet();
for (Map.Entry<Person5,Integer> entry : entries) {
System.out.println(entry);
}
}
}
class Person5 {
String name;
int age;
public Person5() {
}
public Person5(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person5)) return false;
Person5 person5 = (Person5) o;
return age == person5.age &&
Objects.equals(name, person5.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Person5{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

HashMap中的 Key值可以存盤添加 null 值,但是僅僅只能添加一個 null ,因為 Key 中的資料存盤在 Set集合當中的,不可重復,而 Value 值也可以存盤 null值,而且可以存盤多個 null 值,因為 Value 值資料底層是存盤在Collection集合當中的,
舉例:
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
public class HashMapTest {
public static void main(String[] args) {
HashMap<String,Integer> hashMap = new HashMap<String, Integer>();
hashMap.put(null,null);
hashMap.put(null,null);
hashMap.put(null,null);
hashMap.put("1",null);
hashMap.put("2",null);
hashMap.put("3",null);
// 遍歷HashMap 集合
Set<Map.Entry<String,Integer>> entries = hashMap.entrySet();
for (Map.Entry<String,Integer> entry : entries) {
System.out.println(entry);
}
}
}

常用方法總結:
- 添加: put(Object key,Object value)
- 洗掉: remove(object key)
- **修改: **put(Object key,Object value)
- 查詢: get(Object key)
- 長度: size();
- 遍歷: keySet()/values()/entrySet()
3.1 HashMap的存盤結構
JDK 7及以前版本:HashMap是陣列+鏈表結構(即為鏈地址法)
JDK 8版本發布以后:HashMap是陣列+鏈表+紅黑樹實作

如下是 JDK8 的HashMap 結構圖

3.2 HashMap原始碼中的重要常量
/**
* The default initial capacity - MUST be a power of two.
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 HashMap的默認容量是 16
-----------------------------------------------------------------------------------
/**
* The maximum capacity, used if a higher value is implicitly specified
* by either of the constructors with arguments.
* MUST be a power of two <= 1<<30.
*/
static final int MAXIMUM_CAPACITY = 1 << 30; // HashMap的最大支持容量,2^30
-----------------------------------------------------------------------------------
/**
* The load factor used when none specified in constructor.
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f; // HashMap的默認加載因子
-----------------------------------------------------------------------------------
/**
* The bin count threshold for using a tree rather than list for a
* bin. Bins are converted to trees when adding an element to a
* bin with at least this many nodes. The value must be greater
* than 2 and should be at least 8 to mesh with assumptions in
* tree removal about conversion back to plain bins upon
* shrinkage.
*/
static final int TREEIFY_THRESHOLD = 8; // Bucket中鏈表長度大于該默認值,轉化為紅黑樹
-----------------------------------------------------------------------------------
/**
* The bin count threshold for untreeifying a (split) bin during a
* resize operation. Should be less than TREEIFY_THRESHOLD, and at
* most 6 to mesh with shrinkage detection under removal.
*/
static final int UNTREEIFY_THRESHOLD = 6; // Bucket中紅黑樹存盤的Node小于該默認值,轉化為鏈表
-----------------------------------------------------------------------------------
/**
* The smallest table capacity for which bins may be treeified.
* (Otherwise the table is resized if too many nodes in a bin.)
* Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts
* between resizing and treeification thresholds.
*/
static final int MIN_TREEIFY_CAPACITY = 64; // 桶中的Node被樹化時最小的hash表容量,(當桶中Node的數量大到需要變紅黑樹時,若hash表容量小于MIN_TREEIFY_CAPACITY時,此時應執行resize擴容操作這個MIN_TREEIFY_CAPACITY的值至少是TREEIFY_THRESHOLD的4倍,)
-----------------------------------------------------------------------------------
/**
* The table, initialized on first use, and resized as
* necessary. When allocated, length is always a power of two.
* (We also tolerate length zero in some operations to allow
* bootstrapping mechanics that are currently not needed.)
*/
transient Node<K,V>[] table; // 存盤元素的陣列,總是2的n次冪
-----------------------------------------------------------------------------------
/**
* Holds cached entrySet(). Note that AbstractMap fields are used
* for keySet() and values().
*/
transient Set<Map.Entry<K,V>> entrySet; // 存盤具體元素的集合
-----------------------------------------------------------------------------------
/**
* The number of key-value mappings contained in this map.
*/
transient int size; // HashMap中實際存盤的鍵值對的數量
-----------------------------------------------------------------------------------
/**
* The number of times this HashMap has been structurally modified
* Structural modifications are those that change the number of mappings in
* the HashMap or otherwise modify its internal structure (e.g.,
* rehash). This field is used to make iterators on Collection-views of
* the HashMap fail-fast. (See ConcurrentModificationException).
*/
transient int modCount; // HashMap擴容和結構改變的次數,
-----------------------------------------------------------------------------------
/**
* The next size value at which to resize (capacity * load factor).
*
* @serial
*/
// (The javadoc description is true upon serialization.
// Additionally, if the table array has not been allocated, this
// field holds the initial array capacity, or zero signifying
// DEFAULT_INITIAL_CAPACITY.)
int threshold; // 擴容的臨界值,=容量 * 填充因子
-----------------------------------------------------------------------------------
/**
* The load factor for the hash table.
*
* @serial
*/
final float loadFactor; // 填充因子
3.3 HashMap的存盤結構:JDK 1.8之前 / JDK 1.8之后
3.3.1 JDk 1.8 之前
-
HashMap 內部存盤結構其實是
陣列 + 鏈表的結合,當實體化一個 new HashMap() 時,實際上會創建一個長度為 Capacity 的 Entry 陣列,這個長度在 哈希表中稱為 容量(Capacity) ,在這個陣列中可以存放元素的位置,我們稱之為 ”桶“ (bucket) ,每個 bucket 都有自己的索引,系統可以根據索引快速的查找 bucket 中的元素, -
每個bucket 中存盤一個元素,即 一個 Entry 物件內部類 ,但每一個 Entry 物件可以帶 一個參考變數,用于指向下一個元素,因此,在一個桶 (bucket) 中,就有可能生成一個 Entry 鏈,而且新添加的元素作為鏈表的 head ,
-
JDK7 原始碼分析如下:



3.3.2 JDk 1.8 及之后
JDK8: HashMap 的內部存盤結構其實是:陣列+鏈表+樹 的結合,當實體化一個 new HashMap 時,會初始化 initilCapacity 和 loadFactor ,在 put() 第一對映射關系(鍵值對)添加時,系統會創建一個長度為 initilCapacity 的 Node 陣列 ,這個長度在哈希表中被稱為 ”容量" (Capacity),在這個陣列中可以存放元素的位置,我們稱之為 “桶”(bucket) ,每個 bucket 都有自己的索引,系統可以根據索引快速的查找 bucket 中的元素,
每個bucket 中存盤一個元素資料,既 一個 Node 物件,但每一個 Node 物件可以帶一個參考變數 next ,用于指向下一個元素,因此,在一個桶中,就有可能生成一個 Node 鏈表,也可能是一個一個TreeNode 物件,每一個TreeNode 物件可以有兩個葉子節點 left 和 right ,因此,在一個桶中,就有可能生成一個 TreeNode 樹,而新添加的元素作為鏈表的 last ,或樹的葉子節點,
JDK1.8 原始碼分析:




3.3.3 JDK8 HashMap 集合添加元素的程序
向 HashMap 集合中添加 put(key1,value1) 鍵值對, 首先呼叫 元素 key1 所在類的 hashCode() 方法,來得到該 key1物件的 hashCode(哈希) 值,
然后再根據得到的 hashCode (哈希)值,通過某種散列函式 計算除該物件在 HashSet 集合中底層Node[] 陣列的存盤位置(即為:索引下標位置),(這個散列函式會與底層陣列的長度相計算得到在陣列中的下標,并且這種散列函式計算還盡可能保證能均勻存盤元素,越是散列分布,該散列函式設計的越好),
-
判斷此計算處理得到的陣列下標位置上是否已經有元素存盤了 :
- 如果沒有其他元素資料存盤,則 元素 key1-value1添加到該位置上, —— 情況1
- 如果有其它元素資料存盤(或以鏈表形式存盤的多個元素) : 則比較key1和已經存在的一個或多個資料的哈希值):
-
如果 key1的hashCode() 哈希值與已經存在的資料的哈希值都 不相等, 則元素 key1-value1添加到該陣列鏈表上,—— 情況2
-
如果 key1 的hashCode() 哈希值 與 已經存在的資料的哈希值都 相等, 則呼叫 key1 元素所在類的 equals() 方法,, 判斷比較所存盤的內容是否和集合中存盤的相等,
- 如果 不相等 也就是 equals() 方法,回傳 false ,則此時 key1-value1添加成功,—— 情況3
- 如果 相等 也就是 equals()方法,回傳 true,不添加,替換掉其中存放的 value 值為 value1 ,因為 key1 是唯一的不可重復的,但是其 對應的 value 值是可以重復的,
-
-
對應上述 添加成功的 情況2 和 情況3 而言,關于情況2和情況3:此時key1-value1和原來的資料以鏈表的方式存盤
-
如下是 添加鍵值對的程序的圖示:

如下是查找圖示:

假設將所有的hashCode()方法回傳設定為不一樣的值,可以嗎?,有什么問題:
不行,因為這樣的話,就導致 HashMap 集合底層的哈希表就成為了一維陣列了,沒有鏈表的概念了,更沒有哈希表的概念了,
假設將所有的hashCode()方法回傳設回傳值固定為某個值,可以嗎?,有什么問題:
答:不可以,設將所有的hashCode()方法,回傳值固定為某個值,那么會導致底層哈希表變成了純單向鏈表,這種情況下我們稱為:散列分別不均勻,
什么時散列分布不均勻
假設我們有 100 個元素,10個單向鏈表,那么每個單向鏈表上有10個節點,這是最好的,是散列分布均勻的
3.3.4 JDK8 HashMap 進行 "擴容"和 "樹形化"
擴容
當 put(Key1,value1) 添加鍵值對個數超過 陣列大小(陣列總大小 length ,不是陣列中實際存放的鍵值對個數 size),時,就會進行陣列擴容,loadFactor 的默認值:DEFAULT_LOAD_FACTOR)為0.75,這是一個折中的取值,也就是說,默認情況下,陣列大小(DEFAULT_INITIAL_CAPACITY)為16 ,那么當 HashMap 中元素個數超過 16 * 0.75 = 12 (這個值就是代碼中的 threshold值,也叫臨界值)的時候,就把陣列的大小擴展為 2 * 16 = 32 ,即擴大 1倍 ,然后重新計算每個元素在陣列中的位置,而這是一個非常消耗性能的操作,所以在開發中如果我們可以預估計其存盤的資料量,也就是 HashMap中存盤元素的個數,那么就呼叫其HashMap(int num) 設定存盤容量的大小,減少擴容次數,提高 HashMap的性能 ,

樹形化
當HashMap中的其中一個鏈的物件個數如果達到了8個,此時如果capacity沒有達到64,那么HashMap會先擴容解決,如果已經達到了64,那么這個鏈會變成樹,結點型別由Node變成TreeNode型別,當然,如果當映射關系被移除后,下次resize方法時判斷樹的結點個數低于6個,也會把樹再轉為鏈表,

補充:
關于映射關系的key是否可以修改 ???
answer:不要修改,映射關系存盤到 HashMap 中會存盤 key 的 哈希值 ,這樣就不用每次查找時,重新計算每一個 Entry 或 Node (TreeNode)的 哈希值了,因此如果已經 put 到 Map 中的映射關系,再修改 key 的屬性,而這個屬性有參與 hashCode值的計算,那么會導致匹配不上,
為什么HashMap擴容時,不是陣列滿了的時候擴容而是達到一個的 0.75 的額度才擴容 ???
因為HashMap 集合的底層時由 鏈表 + 陣列 + 樹 構成的,由于鏈表的存在,HashMap 當中的陣列不一定會存盤滿了,
以及涉及到 HashMap 集合性能最優的效果,散列均勻分布,所以是到達一定額度 0.75 是最好的情況了.
負載因子值的大小,對HashMap有什么影響 ???
/** * The load factor used when none specified in constructor. */ static final float DEFAULT_LOAD_FACTOR = 0.75f; // HashMap的默認加載因子負載因子的大小決定了HashMap的資料密度,
負載因子越大密度越大,發生碰撞的幾率越高,陣列中的鏈表越容易長,
造成查詢或插入時的比較次數增多,性能會下降,
負載因子越小,就越容易觸發擴容,資料密度也越小,意味著發生碰撞的
幾率越小,陣列中的鏈表也就越短,查詢和插入時比較的次數也越小,性能會更高,但是會浪費一定的內容空間,而且經常擴容也會影響性能,建議初始化預設大一點的空間,
按照其他語言的參考及研究經驗,會考慮將負載因子設定為0.7~0.75,此時平均檢索長度接近于常數,
3.3.5 總結:JDK1.8 相較于之前的變化:
-
JDK8 :HashMap map = new HashMap() ,默認情況下,是不會先創建長度為 16 的 陣列的,而是首先呼叫 map.put() 添加鍵值對的時候創建 長度為 16的陣列(類比:單例模式中的餓漢式), JDK7 則是默認先創建了一個長度為 16的陣列(類比:單例模式中的懶漢式),
-
JDK8 底層的陣列是 Node[ ] ,JDK7 底層的陣列是 Entry[ ] ,
-
put(Key1,Value1) 添加鍵值對時,JDK7 是添加到鏈表上的頭部(陣列上),JDK8 是添加到鏈表的尾部(不在陣列上),簡稱:七上八下,
-
jdk7 底層結構只有:陣列 + 鏈表,jdk8 中底層結構: 陣列 + 鏈表 + 紅黑樹
當陣列的某一個索引位置上的元素以鏈表形式存在的資料個數 > 8 且當前陣列的長度 > 64時,此時此索引位置上的所有資料改為使用“紅黑樹”存盤,當小于 8 時,有會變成鏈表的形式存盤,
4. Map實作類之二:LinkedHashMap



- LinkedHashMap 是 HashMap 的子類,所以 LinkedHashMap 繼承了 HashMap 的特點:其中的 key 是無序,不可重復的,其 Key 存盤的元素類必須重寫 eqauls() 和 hashCode() 方法,同樣的 Key 值是存盤在 Set 集合當中的,而Value 則是存盤在 Collection 集合當中的,
- LinkedHashMap 是在 HashMap 存盤結構的基礎上,使用了一對雙向鏈表來記錄添加元素的順序的,所以你添加元素資料的順序是怎樣的,取元素資料的順序就是怎樣的,
- 與 LinkedHashSet 類似, LinkedHashMap 可以維護 Map 的迭代順序:迭代順序與 Key-Value 鍵值對的插入順序一致,簡單的說就是:存取順序一樣,
- LinkedHashMap 是繼承了 HashMap 其常用的方法是一樣的,這里就不多說明了,不同的是HashMap 底層的內部類是 Node ,而LinkedHashMap 底層的內部類是Entry ,該內部類繼承了 HashMap.Node<K,V>
HashMap中的內部類:Node

LinkedHashMap中的內部類:Entry

舉例:
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
public class LinkedHashMapTest {
public static void main(String[] args) {
// 創建 LinkedHashMap 集合物件
LinkedHashMap<String,Integer> linkedHashMap = new LinkedHashMap<String, Integer>();
// 添加元素資料(鍵值對)
linkedHashMap.put("lihua",99);
linkedHashMap.put("zhangsan",89);
linkedHashMap.put("lisi",79);
linkedHashMap.put("wangwu",69);
// 遍歷 LinkedHashMap 集合
// 獲取到key-value 存盤的 Set Entry 內部類集合物件
Set<Map.Entry<String, Integer>> entries = linkedHashMap.entrySet();
// 獲取到該 Set Entry 內部類集合的迭代器
Iterator<Map.Entry<String, Integer>> iterator = entries.iterator();
while(iterator.hasNext()) {
Map.Entry<String, Integer> entry = iterator.next();
System.out.println(entry.getKey() + "--->" + entry.getValue());
}
}
}

5. Map實作類之三:TreeMap



-
TreeMap 存盤 Key-Value 鍵值對時,需要根據 key-value 鍵值對進行排序,TreeMap 可以保證所有的 key-value 鍵值對處于有序狀態,
-
TreeSet 底層 就是由 TreeMap 構成的,new TreeSet 底層實際上說就是 new TreeMap 集合存盤資料,向 TreeSet 中添加資料就是向 TreeMap 集合中添加資料,
-
TreeMap 中的 key 存盤的資料型別必須是一致的,不然無法比較判斷,從而排序,
-
TreeMap 的 排序是對 Key 的內容進行排序的,其中的 Key 值內部是由 Set 集合存盤的,無序,不可重復性,所存盤類必須重寫 equals() 和 hashCode() 方法,因為會自動排序,所以還需要實作排序:兩種方式一種是:
- 自然排序: TreeMap 的所有的 Key 必須實作(實作
java.lang.Comparable的介面,而且所有 的 Key 應該是同一個類的物件(因為不是同一型別無法比較判斷),否則將會拋出ClasssCastException自然排序,重寫其中的compareTo()抽象方法) ,在Java當中所有的包裝類和String都實作了該java.lang.Comparable介面,所以一般要實作該介面的都是自定的類, - 定制排序: 創建 TreeMap 時,傳入一個 Comparator 物件,該物件負責對 TreeMap 中的所有 key 進行排序,此時不需要 Map 的 Key 實作 Comparable 介面
public TreeMap(Comparator<? super K> comparator)v // 構造一個新的,空的樹圖,按照給定的比較器排序,- 關于自然排序與 定制排序 的詳解內容大家可以移步至:?????? 比較器: Comparable 與 Comparator 區別_ChinaRainbowSea的博客-CSDN博客
- 自然排序: TreeMap 的所有的 Key 必須實作(實作
-
TreeMap 判斷兩個 Key 相等的標準:兩個 key 通過 重寫的 compareTo()方法或 compare()方法,回傳0 表示相等,
舉例:
TreeMap 集合中存盤自定義類 Person6 物件,其中的 Key 存盤的類為自定義 Person6 物件,該物件重寫了 equals() 和 hashCode()方法,但是沒有重寫比較器的情況,報例外:java.lang.ClassCastException 型別轉換例外,
將其中的Person6 中 age 年齡,升序排列

import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
public class TreeMapTest {
public static void main(String[] args) {
// 創建TreeMap 集合物件,其中 Key 存盤的類為自定義 Person6
TreeMap<Person6,Integer> treeMap = new TreeMap<Person6,Integer>();
// 添加元素
treeMap.put(new Person6("lihua",18),99);
treeMap.put(new Person6("zhangsan",20),89);
treeMap.put(new Person6("lisi",25),79);
treeMap.put(new Person6("wangwu",19),69);
// 遍歷集合
// 遍歷 TreeMap 集合
// 獲取到key-value 存盤的 Set Entry 內部類集合物件
Set<Map.Entry<Person6, Integer>> entries = treeMap.entrySet();
// 獲取到該 Set Entry 內部類集合的迭代器
Iterator<Map.Entry<Person6, Integer>> iterator = entries.iterator();
while(iterator.hasNext()) {
Map.Entry<Person6, Integer> entry = iterator.next();
System.out.println(entry.getKey() + "--->" + entry.getValue());
}
}
}
class Person6 {
String name;
int age;
public Person6() {
}
public Person6(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
// 當物件中的 name 和 age 屬性值相同回傳 true,否則回傳 fasle
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person6)) return false;
Person6 person6 = (Person6) o;
return getAge() == person6.getAge() &&
Objects.equals(getName(), person6.getName());
}
@Override
public int hashCode() {
return Objects.hash(getName(), getAge());
}
@Override
public String toString() {
return "Person6{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
修正: 對 Key 中所存盤的類,提供比較器,方式一:自然排序,該存盤類實作 java.lang.Comparable介面,并重寫其中的 CompareTo()重寫方法,
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
public class TreeMapTest {
public static void main(String[] args) {
// 創建TreeMap 集合物件,其中 Key 存盤的類為自定義 Person6
TreeMap<Person6,Integer> treeMap = new TreeMap<Person6,Integer>();
// 添加元素
treeMap.put(new Person6("lihua",18),99);
treeMap.put(new Person6("zhangsan",20),89);
treeMap.put(new Person6("lisi",25),79);
treeMap.put(new Person6("wangwu",19),69);
// 遍歷集合
// 遍歷 TreeMap 集合
// 獲取到key-value 存盤的 Set Entry 內部類集合物件
Set<Map.Entry<Person6, Integer>> entries = treeMap.entrySet();
// 獲取到該 Set Entry 內部類集合的迭代器
Iterator<Map.Entry<Person6, Integer>> iterator = entries.iterator();
while(iterator.hasNext()) {
Map.Entry<Person6, Integer> entry = iterator.next();
System.out.println(entry.getKey() + "--->" + entry.getValue());
}
}
}
class Person6 implements Comparable<Person6>{
String name;
int age;
public Person6() {
}
public Person6(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
// 當物件中的 name 和 age 屬性值相同回傳 true,否則回傳 fasle
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person6)) return false;
Person6 person6 = (Person6) o;
return getAge() == person6.getAge() &&
Objects.equals(getName(), person6.getName());
}
@Override
public int hashCode() {
return Objects.hash(getName(), getAge());
}
/**
* 升序的比較規則:
* this > 引數 ,回傳 > 0
* this < 引數,回傳 < 0
* this == 引數,回傳 == 0;
* 降序反過來:
* this > 引數 ,回傳 < 0
* this < 引數,回傳 > 0
* this == 引數,回傳 == 0;
*/
@Override
public int compareTo(Person6 o) {
// 首先判斷該需要比較的引數是否是同一個實體,同一個實體的物件才能比較
if(o instanceof Person6) { // 其實這里我們使用了<Person3 o> 泛型限定了,就不需要判斷了
Person6 person6 = (Person6) o; // 是對應的實體向下轉型,
if(this.age > person6.age) {
return 1;
} else if( this.age < person6.age) {
return -1;
} else {
return 0;
}
} else {
// throw 可以替代 return
throw new RuntimeException("型別不一致"); // 拋出運行時例外
}
}
@Override
public String toString() {
return "Person6{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

修改方式二:定制排序 創建 TreeMap 集合物件時,將一個匿名實作Com 的類,作為引數,傳遞給構造器,該匿名實作類定制排序按照你 Perso6 中的 age 年齡降序排列
public TreeMap(Comparator<? super K> comparator); // 構造一個新的,空的樹圖,按照給定的比較器排序,
package blogs.blogs7;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
public class TreeMapTest {
public static void main(String[] args) {
// 創建一個 TreeMap 集合物件,將匿名實作的比較器(定制排序),作為引數,傳遞給構造器
TreeMap<Person6,Integer> treeMap = new TreeMap<Person6,Integer>(new Comparator<Person6>() {
@Override
public int compare(Person6 o1, Person6 o2) {
// 判斷是否是對應比較的實體,其實這里我們可以不用判斷的,因為使用的泛型限定
if(o1 instanceof Person6 && o2 instanceof Person6) {
Person6 p1 = (Person6)o1;
Person6 p2 = (Person6)o2; // 向下轉型為對應的實體物件,從而獲取比較屬性
if(p1.age > p2.age) {
return -1;
} else if(p1.age < p2.age) {
return 1;
} else {
return 0;
}
}
// throw 可以代替 return
throw new RuntimeException("型別不一致"); // 拋出運行時例外
}
});
// 添加元素
treeMap.put(new Person6("lihua",18),99);
treeMap.put(new Person6("zhangsan",20),89);
treeMap.put(new Person6("lisi",25),79);
treeMap.put(new Person6("wangwu",19),69);
// 遍歷集合
// 遍歷 TreeMap 集合
// 獲取到key-value 存盤的 Set Entry 內部類集合物件
Set<Map.Entry<Person6, Integer>> entries = treeMap.entrySet();
// 獲取到該 Set Entry 內部類集合的迭代器
Iterator<Map.Entry<Person6, Integer>> iterator = entries.iterator();
while(iterator.hasNext()) {
Map.Entry<Person6, Integer> entry = iterator.next();
System.out.println(entry.getKey() + "--->" + entry.getValue());
}
}
}
class Person6 implements Comparable<Person6>{
String name;
int age;
public Person6() {
}
public Person6(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
// 當物件中的 name 和 age 屬性值相同回傳 true,否則回傳 fasle
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person6)) return false;
Person6 person6 = (Person6) o;
return getAge() == person6.getAge() &&
Objects.equals(getName(), person6.getName());
}
@Override
public int hashCode() {
return Objects.hash(getName(), getAge());
}
@Override
public String toString() {
return "Person6{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

6. Map實作類之四:Hashtable



- Hashtable 是個古老的 Map 實作類,JDK1.0 就提供了,不同于 HashMap ,Hashtable 是執行緒安全的,其中的方法基本上都不被
synchronized, - Hashtable 實作原理和 HashMap 相同,功能相同,底層都使用哈希結構,速度快,很多情況下可以互用,
- Hashteble 與 HashMap 不同,Hashtable 不允許使用 null 作為 Key 和 Value 的值,不然報,
java.lang.NullPointerException空指標例外, - Hashtable 與 HashMap 一樣,Hashtable 也不能保證其中 Key-Value 鍵值對的順序,
- 同樣的 其中的 Key 值內部是由 Set 集合存盤的,無序,不可重復性,所存盤類必須重寫 equals() 和 hashCode() 方法,
- Hashtable 判斷兩個 key 相等,兩個 value 相等的標準,與 HashMap 是一樣的,Hashtable和HashMap 一樣,底層都是哈希表的資料結構,Hashtable 的初始容量為 11,默認加載因子是 : 0.75,Hashtable 的擴容:
原容量 * 2 + 1;
HashMap和HashTable的比較:
舉例 :


import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashtableTest {
public static void main(String[] args) {
Hashtable<String,Integer> hashtable = new Hashtable<String,Integer>();
hashtable.put("lihua",1);
hashtable.put("zhangsan",2);
hashtable.put("lisi",3);
hashtable.put("wangwu",4);
Set<Map.Entry<String, Integer>> entries = hashtable.entrySet();
Iterator<Map.Entry<String, Integer>> iterator = entries.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}

7. Map實作類之五:Properties



- Properties 類是 Hashtable 的子類,該物件用于處理讀取屬性檔案,
- 由于屬性檔案里的 key,value都是字串型別的,所以 Properties 里的 key 和 value 都是字串型別 ,
- 存取資料時,建議使用 setProperty(String key,String value) 方法 和 getProperty(String key) 方法,
public Object setProperty(String key,String value); // 致電Hashtable方法put , 提供與getProperty方法的并行性 , 強制使用字串的屬性鍵和值, 回傳的值是Hashtable呼叫put的結果,簡單的說:就是向Property 集合中添加鍵值對元素,
public String getProperty(String key); // 通過 key 找到對應的 value值,如果沒有找到回傳 null
舉例:
首先我們先在專案中(注意添加到頂級專案中也就是如下的Test 專案下,不是Test2,或者 day模塊下 ,不然無法讀取到)添加一個屬性檔案(以.properties后綴的組態檔)用于Properties 集合讀取,內容如下:

name=Tom
password=abc123
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class PropertiesTest {
public static void main(String[] args) {
// Properties 集合常用來處理組態檔:key 和 value 都是String型別
Properties properties = new Properties();
try {
// IO流讀取檔案資訊,需要例外處理
FileInputStream fileInputStream = new FileInputStream("jdbc.properties"); // 檔案名
properties.load(fileInputStream); // 加載流對應的檔案,同樣需要例外處理
} catch (IOException e) {
throw new RuntimeException(e);
}
String name = properties.getProperty("name");
String password = properties.getProperty("password"); // 根據對應檔案中的 key 值獲取到對應的value值
System.out.println(name);
System.out.println(password);
}
}

8. Map 介面下的集合遍歷方式
Map 介面下的集合的遍歷方式:注意:Map 集合中沒有下標可以訪問的,也沒有迭代器可以使用的,
方式一: 普遍使用,二次取值,通過獲取 keySet() 方法獲取到 Map 集合中所有的 key 值,回傳一個 Set 集合,再通過遍歷 Set 集合中存盤的所有的 key ,使用 get(key) 方法獲取到對應的 value值,
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Traverse {
// Map 集合遍歷方式一:
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("1", "value1");
map.put("2", "value2");
map.put("3", "value3");
// 1.獲取到該 Map 集合當中的所有 Key 值
Set<String> keys = map.keySet();
// 2.遍歷所有的 key 值
for (String key : keys) {
// 3. 通過 key 獲取到對應的 value 值
System.out.println(key + "--->" + map.get(key));
}
}
}

方式二: 通過使用 entrySet() 方法,回傳一個:Set< Map.Entry<K, V> > 集合物件, 再通過獲取到該 Set<Map.Entry> 集合 的迭代器,通過迭代器遍歷,獲取到Map.Entry中存盤的 key(getKey()), value(getVale()) 方法
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Traverse {
// Map 集合遍歷方式二:
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("1", "value1");
map.put("2", "value2");
map.put("3", "value3");
// 1. 獲取到 Set<Map.Entry> 集合物件
Set<Map.Entry<String, String>> entries = map.entrySet();
// 2. 獲取到該 Set<Map.Entry> 集合 的迭代器
Iterator<Map.Entry<String, String>> iterator = entries.iterator();
// 3. 通過迭代器遍歷,獲取到Map.Entry中存盤的 key,value值
while(iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
System.out.println(entry.getKey() + "--->" + entry.getValue());
}
}
}

方式三: 推薦,尤其是容量大時,因為這是一次性獲取到 Map 中所有的key-value 值后,再取出的,效率高
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Traverse {
// Map 集合遍歷方式三:
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("1", "value1");
map.put("2", "value2");
map.put("3", "value3");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + "--->" + entry.getValue());
}
}
}

方式四: 通過Map.values() 回傳一個Collection 集合遍歷所有的value,但不能遍歷key
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Traverse {
// Map集合遍歷方式四:
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("1", "value1");
map.put("2", "value2");
map.put("3", "value3");
// 獲取到集合當中所有的 value值
Collection<String> values = map.values();
for (String value : values) {
System.out.println(value);
}
}
}

9. Collections工具類
一個獨立的集合 工具類


- Collections 是一個操作 Set,List 和 Map 等集合的工具類,
- 注意區別:Collection 是一個介面集合,而 Collection
s多了個 s 的是 集合工具類,都是在java.util.包下的, - Collections 中提供了一系列靜態的方法(工具方法麻,一般都是靜態方法)對集合元素進行排序,查詢和修改等操作,還提供了對集合物件設定不可變,對集合物件實作同步控制(解決執行緒安全問題)等方法,
9.1 Collections常用方法
排序:
- reverse(List lsit) : 反轉 List 中元素的順序
public static void reverse(List<?> list); // 反轉 List 中元素的順序
- shuffle(List list): 對 List 集合元素進行隨機排序
public static void shuffle(List<?> list); // 對 List 集合元素進行隨機排序
- sort(List list) : 根據元素的自然順序對指定 List 集合元素按升序排序,注意的是: 排序需要存盤的類有比較器呼叫 自然排序(實作
java.lang.Comparable的介面 / 定制排序 Comparator介面)
public static <T extends Comparable<? super T>> void sort(List<T> list); // 根據元素的自然順序對指定 List 集合元素按升序排序
- sort(List list, Comparator c) : 根據指定的 Comparator 產生的順序對 List 集合元素進行排序
public static <T> void sort(List<T> list,Comparator<? super T> c); // 根據指定的 Comparator 產生的順序對 List 集合元素進行排序
- swap(List list , int i , int j ) : 將指定 list 集合中的 i 處元素和 j 處元素進行交換,注意是左閉右開的,
public static void swap(List<?> list,int i,int j); // 將指定 list 集合中的 i 處元素和 j 處元素進行交換
查找,替換 :
- max(Collection c) : 根據元素的自然順序,回傳給定集合中的最大元素,
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll); // 根據元素的自然順序,回傳給定集合中的最大元素
- max(Collection coll, Comarator comp) : 根據Comparator 指定的順序,回傳給定集合中的最大元素,
public static <T> T max(Collection<? extends T> coll,Comparator<? super T> comp); // 根據 Comparator 指定的順序,回傳給定集合中的最大元素
- min(Collection c) : 根據元素的自然順序,回傳給定集合中的最小元素,
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll); // 根據元素的自然順序,回傳給定集合中的最小元素,
- min(Collection coll, Comarator comp) : 根據Comparator 指定的順序,回傳給定集合中的最小元素,
public static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp); // 根據Comparator 指定的順序,回傳給定集合中的最小元素,
- replaceAll(List list,T oldVal,T newVal) : 用新值替換List 物件的所有舊值,注意存盤的類需要重寫 equals()方法,才能比較判斷找到對應替換的值,
public static <T> boolean replaceAll(List<T> list,T oldVal,T newVal); // 用新值替換List 物件的所有舊值.
- frequency(Collection c , Object o) : 回傳指定集合中指定元素的出現次數,注意 :存盤的類需要重寫 equals()方法才能比較判斷查找對應的值的個數,
public static int frequency(Collection<?> c,Object o); // 回傳指定集合中指定元素的出現次數
- copy(List dest,List src) : 將 src 集合中的內容復制到 dest 集合當中,
public static <T> void copy(List<? super T> dest,List<? extends T> src); // 將 src 集合中的內容復制到 dest 集合當中
注意該 copy(List dest,List src) 方法,兩個集合物件存盤的資料型別是必須是一樣的,不然無法拷貝添加到 dest 集合當中的,
還有拷貝存盤到的物件 dest 的 size()長度 < 被拷貝的 src 的 size()長度 就會拷貝失敗,報例外: IndexOutOfBoundsException
所以拷貝存盤到的物件 dest 的 size()長度 必須 >= 被拷貝的 src 的 size()長度 ,注意是 size()實際存盤元素資料的長度,不是length()集合的長度 ,
如下原始碼:

舉例 : 解決思路如下:
package blogs.blogs7;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class CollectionsTest {
public static void main(String[] args) {
List<Integer> src = https://www.cnblogs.com/TheMagicalRainbowSea/archive/2023/02/03/new ArrayList();
src.add(1);
src.add(99);
src.add(-1);
src.add(66);
// 創建一個 和 src 集合存盤型別一樣的 Arrays.asList(new Integer[src.size()])陣列,并設定該陣列的大小長度為 src.size()
// 再使用這個陣列創建拷貝存盤的 desc 集合物件,默認陣列沒有添加資料(這里的是 null)
// 這樣就 desc 就擁有了一個和 sec集合一樣大小的 size()長度了,
List desc = new ArrayList();
desc = Arrays.asList(new Integer[src.size()]);
for (Integer integer : desc) {
System.out.println(integer);
}
// copy()拷貝
Collections.copy(desc, src);
System.out.println("*********** 拷貝 ************");
for (Integer num : desc) {
System.out.println(num);
}
}
}

10. 總結:
補充 :各個集合的轉換,可以使用對應的方法,或構造器
@Test
public void test2() {
Set<String> set = new HashSet<>();
set.add("king");
set.add("kingsoft");
set.add("king2");
set.add("king1");
// 將Set集合轉換成List集合
List<String> myList = new ArrayList<>(set);
for(String s : myList) {
System.out.println(s);
}
}


- Map 介面下的集合的特點:集合的key 就是一個 Set 集合存盤的,而 value 值則是被 Collectio介面集合存盤的,
在Set 集合中放資料,實際上放到了Map集合的key 部分中去了, - 注意:Map集合中的 Key 都是存盤在 Set 集合當中的(該集合無序,不可重復),所以Map集合當中的 key 存盤的類必須重寫
equals() 和 hashCode()方法,不然無法處理 Key 的不可重復特點 ,,但是其中的 value 值是可以存盤重復的資料的,而 value 值則是被 Collection 介面集合存盤的, - Map 介面與 Collection 并列存在的,用于保存具有映射關系的資料:key-value 被稱為 鍵值對 ,一個key-value 構成一個
Map.Entry,所有的 Map.Entry 構成的集合是 Set 無序的,不可重復的, - 理解 HashMap 中的 put() 添加鍵值對元素資料的原理,以及擴容,和樹化的機制,區別 JDK7 / JDK8 的機制不同點
- TreeMap 的 排序是對 Key 的內容進行排序的,其中的 Key 值內部是由 Set 集合存盤的,無序,不可重復性,所存盤類必須重寫 equals() 和 hashCode() 方法,因為會自動排序,所以還需要實作排序:兩種方式一種是:
- 自然排序: TreeMap 的所有的 Key 必須實作(實作
java.lang.Comparable的介面,而且所有 的 Key 應該是同一個類的物件(因為不是同一型別無法比較判斷),否則將會拋出ClasssCastException自然排序,重寫其中的compareTo()抽象方法) ,在Java當中所有的包裝類和String都實作了該java.lang.Comparable介面,所以一般要實作該介面的都是自定的類, - 定制排序: 創建 TreeMap 時,傳入一個 Comparator 物件,該物件負責對 TreeMap 中的所有 key 進行排序,此時不需要 Map 的 Key 實作 Comparable 介面
- 自然排序: TreeMap 的所有的 Key 必須實作(實作
11. 最后:
限于自身水平,其中存在的錯誤,希望大家給予指教,韓信點兵——多多益善,謝謝大家,后會有期,江湖再見!!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/542934.html
標籤:其他
下一篇:python語法進階這一篇就夠了


