Java中的集合(下)

### 11.3.3 List實現(xiàn)類的區(qū)別

#### 1、Vector和ArrayList的區(qū)別

核心類庫中List接口有兩個實現(xiàn)類:Vector和ArrayList。它們的底層物理結構都是數(shù)組,我們稱為動態(tài)數(shù)組。

(1)ArrayList是新版的動態(tài)數(shù)組,線程不安全,效率高,Vector是舊版的動態(tài)數(shù)組,線程安全,效率低。

(2)動態(tài)數(shù)組的擴容機制不同,ArrayList擴容為原來的1.5倍,Vector擴容增加為原來的2倍。

(3)數(shù)組的初始化容量,如果在構建ArrayList與Vector的集合對象時,沒有顯式指定初始化容量,那么Vector的內部數(shù)組的初始容量默認為10,而ArrayList在JDK1.6及之前的版本也是10,JDK1.7之后的版本ArrayList初始化為長度為0的空數(shù)組,之后在添加第一個元素時,再創(chuàng)建長度為10的數(shù)組。

ArrayList在第1次添加時再創(chuàng)建數(shù)組是為了避免浪費。因為很多方法的返回值是ArrayList類型,需要返回一個ArrayList的對象,例如:后期從數(shù)據庫查詢對象的方法,返回值很多就是ArrayList。有可能你要查詢的數(shù)據不存在,要么返回null,要么返回一個沒有元素的ArrayList對象。

#### 2、ArrayList與LinkedList的區(qū)別

動態(tài)數(shù)組底層的物理結構是數(shù)組,因此根據索引訪問的效率非常高。但是==非末尾==位置的插入和刪除效率不高,因為涉及到移動元素。==末尾位置==的插入和刪除不涉及移動元素。另外添加操作時涉及到擴容問題,就會增加時空消耗。

鏈表底層的物理結構是鏈表,因此根據索引訪問的效率不高,但是插入和刪除不需要移動元素,只需要修改前后元素的指向關系即可,而且鏈表的添加不會涉及到擴容問題。

 

## 11.4 棧和隊列

### 11.4.1 棧

堆棧是一種先進后出(FILO:first in last out)或后進先出(LIFO:last in first out)的結構。

棧只是邏輯結構,其物理結構可以是數(shù)組,也可以是鏈表,即棧結構分為順序棧和鏈式棧。

核心類庫中的棧結構有Stack和LinkdeList。Stack就是順序棧,它是Vector的子類。LinkedList是鏈式棧。

體現(xiàn)棧結構的操作方法:

*  peek()方法:查看棧頂元素,不彈出
*  pop()方法:彈出棧
*  push(E e)方法:壓入棧

```java
package com.atguigu.list;
import org.junit.Test;
import java.util.LinkedList;
import java.util.Stack;
public class TestStack {
   @Test
   public void test1(){
       Stack<Integer> list = new Stack<>();
       list.push(1);
       list.push(2);
       list.push(3);
       System.out.println("list = " + list);
       System.out.println("list.peek()=" + list.peek());
       System.out.println("list.peek()=" + list.peek());
       System.out.println("list.peek()=" + list.peek());
/*
        System.out.println("list.pop() =" + list.pop());
        System.out.println("list.pop() =" + list.pop());
        System.out.println("list.pop() =" + list.pop());
        System.out.println("list.pop() =" + list.pop());//java.util.NoSuchElementException
*/
        while(!list.empty()){
           System.out.println("list.pop() =" + list.pop());
       }
   }
   @Test
   public void test2(){
       LinkedList<Integer> list = new LinkedList<>();
       list.push(1);
       list.push(2);
       list.push(3);
       System.out.println("list = " + list);
       System.out.println("list.peek()=" + list.peek());
       System.out.println("list.peek()=" + list.peek());
       System.out.println("list.peek()=" + list.peek());
/*
        System.out.println("list.pop() =" + list.pop());
        System.out.println("list.pop() =" + list.pop());
        System.out.println("list.pop() =" + list.pop());
        System.out.println("list.pop() =" + list.pop());//java.util.NoSuchElementException
*/
       while(!list.isEmpty()){
           System.out.println("list.pop() =" + list.pop());
       }
   }
}
```

### 11.4.2 隊列

隊列(Queue)是一種(但并非一定)先進先出(FIFO)的結構。

隊列是邏輯結構,其物理結構可以是數(shù)組,也可以是鏈表。隊列有普通隊列、雙端隊列、并發(fā)隊列等等,核心類庫中的隊列實現(xiàn)類有很多(后面會學到很多),LinkdeList是雙端隊列的實現(xiàn)類。

==Queue==除了基本的 `Collection`操作外,==隊列==還提供其他的插入、提取和檢查操作。每個方法都存在兩種形式:一種拋出異常(操作失敗時),另一種返回一個特殊值(`null` 或  `false`,具體取決于操作)。`Queue` 實現(xiàn)通常不允許插入  元素,盡管某些實現(xiàn)(如 )并不禁止插入  。即使在允許 null 的實現(xiàn)中,也不應該將  插入到  中,因為  也用作  方法的一個特殊返回值,表明隊列不包含元素。

|      | *拋出異常* | *返回特殊值* |
| ---- | ---------- | ------------ |
| 插入 | add(e)     | offer(e)     |
| 移除 | remove()   | poll()       |
| 檢查 | element()  | peek()       |

==Deque==,名稱 *deque* 是“double ended queue==(雙端隊列)==”的縮寫,通常讀為“deck”。此接口定義在雙端隊列兩端訪問元素的方法。提供插入、移除和檢查元素的方法。每種方法都存在兩種形式:一種形式在操作失敗時拋出異常,另一種形式返回一個特殊值(`null`  或 `false`,具體取決于操作)。Deque接口的實現(xiàn)類有ArrayDeque和LinkedList,它們一個底層是使用數(shù)組實現(xiàn),一個使用雙向鏈表實現(xiàn)。

|          | **第一個元素(頭部)** |               | **最后一個元素(尾部)** |              |
| -------- | ---------------------- | ------------- | ------------------------ | ------------ |
|          | *拋出異常*             | *特殊值*      | *拋出異常*               | *特殊值*     |
| **插入** | addFirst(e)            | offerFirst(e) | addLast(e)               | offerLast(e) |
| **移除** | removeFirst()          | pollFirst()   | removeLast()             | pollLast()   |
| **檢查** | getFirst()             | peekFirst()   | getLast()                | peekLast()   |

此接口擴展了 `Queue`接口。在將雙端隊列用作隊列時,將得到  FIFO(先進先出)行為。將元素添加到雙端隊列的末尾,從雙端隊列的開頭移除元素。從 `Queue` 接口繼承的方法完全等效于  `Deque` 方法,如下表所示:  

| **`Queue` 方法** | **等效 `Deque` 方法** |
| ---------------- | --------------------- |
| add(e)           | addLast(e)            |
| offer(e)         | offerLast(e)          |
| remove()         | removeFirst()         |
| poll()           | pollFirst()           |
| element()        | getFirst()            |
| peek()           | peekFirst()           |

雙端隊列也可用作 LIFO(后進先出)堆棧。應優(yōu)先使用此接口而不是遺留 `Stack` 類。在將雙端隊列用作堆棧時,元素被推入雙端隊列的開頭并從雙端隊列開頭彈出。堆棧方法完全等效于 `Deque` 方法,如下表所示:  

| **堆棧方法** | **等效 `Deque` 方法** |
| ------------ | --------------------- |
| push(e)      | addFirst(e)           |
| pop()        | removeFirst()         |
| peek()       | peekFirst()           |

結論:Deque接口的實現(xiàn)類既可以用作FILO堆棧使用,又可以用作FIFO隊列使用。

```java
package com.atguigu.queue;
import java.util.LinkedList;
public class TestQueue {
   public static void main(String[] args) {
       LinkedList<String> list = new LinkedList<>();
       list.addLast("張三");
       list.addLast("李四");
       list.addLast("王五");
       list.addLast("趙六");
       while (!list.isEmpty()){
           System.out.println("list.removeFirst()=" + list.removeFirst());
       }
   }
}
```

 

## 11.5 Map

### 11.5.1 概述

現(xiàn)實生活中,我們常會看到這樣的一種集合:IP地址與主機名,身份證號與個人,系統(tǒng)用戶名與系統(tǒng)用戶對象等,這種一一對應的關系,就叫做映射。Java提供了專門的集合類用來存放這種對象關系的對象,即`java.util.Map<K,V>`接口。Map接口的常用實現(xiàn)類:HashMap、TreeMap、LinkedHashMap和Properties。其中HashMap是 Map 接口使用頻率最高的實現(xiàn)類。

我們通過查看`Map`接口描述,發(fā)現(xiàn)`Map<K,V>`接口下的集合與`Collection<E>`接口下的集合,它們存儲數(shù)據的形式不同。

* `Collection`中的集合,元素是孤立存在的(理解為單身),向集合中存儲元素采用一個個元素的方式存儲。
* `Map`中的集合,元素是成對存在的(理解為夫妻)。每個元素由鍵與值兩部分組成,通過鍵可以找對所對應的值。
* `Collection`中的集合稱為單列集合,`Map`中的集合稱為雙列集合。
* 需要注意的是,`Map`中的集合不能包含重復的鍵,值可以重復;每個鍵只能對應一個值(這個值可以是單個值,也可以是個數(shù)組或集合值)。

### 11.5.2 Map常用方法

1、添加操作

* V put(K key,V value):添加一對鍵值對
* void putAll(Map<? extends K,? extends V> m):添加一組鍵值對

2、刪除

* void clear():清空map
* V remove(Object key):根據key刪除一對鍵值對
* default boolean remove(Object key,Object value):刪除匹配的(key,value)

3、修改value(JDK1.8新增)

- default V replace(K key, V value):找到目標key,替換value
- default boolean replace(K key,V oldValue,V newValue):找到目標(key,value),替換value
- default void replaceAll(BiFunction<? super K,? super V,? extends V> function):按照指定要求替換value

4、元素查詢的操作

* V get(Object key):根據key返回value
* boolean containsKey(Object key):判斷key是否存在
* boolean containsValue(Object value):判斷value是否存在
* boolean isEmpty():判斷map是否為空
* int size():獲取鍵值對的數(shù)量

5、遍歷

Map的遍歷,不能支持foreach,因為Map接口沒有繼承java.lang.Iterable<T>接口。只能用如下方式遍歷:

(1)分開遍歷:

* 單獨遍歷所有key:Set<K> keySet()
* 單獨遍歷所有value:Collection<V> values()


(2)成對遍歷:

* 遍歷所有鍵值對:Set<Map.Entry<K,V>> entrySet()
* 遍歷的是映射關系Map.Entry類型的對象,Map.Entry是Map接口的內部接口。每一種Map內部有自己的Map.Entry的實現(xiàn)類。在Map中存儲數(shù)據,實際上是將Key---->value的數(shù)據存儲在Map.Entry接口的實例中,再在Map集合中插入Map.Entry的實例化對象,如圖示:

1563725601891.png

(3)調用forEach方法遍歷

- default void forEach(BiConsumer<? super K,? super V> action)  

```java
package com.atguigu.map;
import org.junit.Test;
import java.util.HashMap;
import java.util.function.BiFunction;
public class TestMapMethod {
   @Test
   public void test1(){
       //創(chuàng)建 map對象
       HashMap<String, String> map = new HashMap<String, String>();
       //添加元素到集合
       map.put("黃曉明", "楊穎");
       map.put("文章", "馬伊琍");
       map.put("文章", "姚笛");
       map.put("鄧超", "孫儷");
       System.out.println(map.size());
       System.out.println(map);
   }
   @Test
   public void test2(){
       HashMap<String, String> map = new HashMap<String, String>();
       //添加模范夫妻
       map.put("黃曉明", "楊穎");
       map.put("文章", "馬伊琍");
       map.put("鄧超", "孫儷");
       System.out.println(map);
       //刪除鍵值對
       map.remove("文章");
       System.out.println(map);
       map.remove("黃曉明","楊穎");
       System.out.println(map);
   }
   @Test
   public void test3(){
       HashMap<String, String> map = new HashMap<String, String>();
       //添加夫妻
       map.put("黃曉明", "楊穎");
       map.put("文章", "馬伊琍");
       map.put("鄧超", "孫儷");
       map.put("張三", null);
       System.out.println(map);
       //修改value
       map.replace("文章","姚笛");
       System.out.println(map);
       map.replace("黃曉明","楊穎", "angelababy");
       System.out.println(map);
       map.replaceAll(new BiFunction<String, String, String>() {
           @Override
           public String apply(String key, String value) {
               return value == null ? "如花" : value;
           }
       });
       System.out.println(map);
   }
   @Test
   public void test4(){
       HashMap<String, String> map = new HashMap<String, String>();
       //添加元素到集合
       map.put("黃曉明", "楊穎");
       map.put("文章", "馬伊琍");
       map.put("鄧超", "孫儷");
       // 想要查看 誰的媳婦 是誰
       System.out.println(map.get("黃曉明"));
       System.out.println(map.get("鄧超"));
   }
   
   @Test
   public void test4(){
       HashMap<String, String> map = new HashMap<String, String>();
       //添加元素到集合
       map.put("黃曉明", "楊穎");
       map.put("文章", "馬伊琍");
       map.put("鄧超", "孫儷");
       //遍歷所有key
       System.out.println("所有key:");
       Set<String> keySet = map.keySet();
       for (String key : keySet) {
           System.out.println(key);
       }
       //遍歷所有value
       System.out.println("所有value:");
       Collection<String> values = map.values();
       for (String value : values) {
           System.out.println(value);
       }
       //遍歷所有鍵值對
       System.out.println("所有鍵值對:");
       Set<Map.Entry<String, String>> entries = map.entrySet();
       for (Map.Entry<String, String> entry : entries) {
           System.out.println(entry);
       }
       //調用forEach方法遍歷所有鍵值對
       System.out.println("所有鍵值對:");
       BiConsumer<String,String> c = new BiConsumer<>() {
           @Override
           public void accept(String key, String value) {
               System.out.println(key+" vs "+value);
           }
       };
       map.forEach(c);
   }
   
}
```

### 11.5.3 Map接口的實現(xiàn)類們

#### **1、HashMap和Hashtable**

HashMap和Hashtable都是哈希表。HashMap和Hashtable判斷兩個 key 相等的標準是:兩個 key 的hashCode 值相等,并且 equals() 方法也返回 true。因此,為了成功地在哈希表中存儲和獲取對象,用作鍵的對象必須實現(xiàn) hashCode 方法和 equals 方法。


* Hashtable是線程安全的,任何非 null 對象都可以用作鍵或值。

* HashMap是線程不安全的,并允許使用 null 值和 null 鍵。


示例代碼:添加員工姓名為key,薪資為value

```java
package com.atguigu.map;
import org.junit.Test;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
public class TestHashMap {
   @Test
   public void test01(){
       HashMap<String,Double> map = new HashMap<>();
       map.put("張三", 10000.0);
       //key相同,新的value會覆蓋原來的value
       //因為String重寫了hashCode和equals方法
       map.put("張三", 12000.0);
       map.put("李四", 14000.0);
       //HashMap支持key和value為null值
       String name = null;
       Double salary = null;
       map.put(name, salary);
       System.out.println(map);
     
   }
   @Test
   public void test02(){
       Hashtable<String,Double> map = new Hashtable<>();
       map.put("張三", 10000.0);
       //key相同,新的value會覆蓋原來的value
       //因為String重寫了hashCode和equals方法
       map.put("張三", 12000.0);
       map.put("李四", 14000.0);
       //Hashtable不支持key和value為null值
       /*String name = null;
       Double salary = null;
       map.put(name, salary);*/
       System.out.println(map);
   }
}
```

#### **2、LinkedHashMap**

LinkedHashMap 是 HashMap 的子類。此實現(xiàn)與 HashMap 的不同之處在于,后者維護著一個運行于所有條目的雙重鏈接列表。此鏈接列表定義了迭代順序,該迭代順序通常就是將鍵插入到映射中的順序(插入順序)。

示例代碼:添加員工姓名為key,薪資為value

```java
package com.atguigu.map;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
public class TestLinkedHashMap {
   public static void main(String[] args) {
       LinkedHashMap<String,Double> map = new LinkedHashMap<>();
       map.put("張三", 10000.0);
       //key相同,新的value會覆蓋原來的value
       //因為String重寫了hashCode和equals方法
       map.put("張三", 12000.0);
       map.put("李四", 14000.0);
       //HashMap支持key和value為null值
       String name = null;
       Double salary = null;
       map.put(name, salary);
       System.out.println(map);
   }
}
```

#### **3、TreeMap**

基于紅黑樹(Red-Black tree)的 NavigableMap 實現(xiàn)。該映射根據其鍵的自然順序進行排序,或者根據創(chuàng)建映射時提供的 Comparator 進行排序,具體取決于使用的構造方法。

代碼示例:添加員工姓名為key,薪資為value

```java
package com.atguigu.map;
import java.util.Comparator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import org.junit.Test;
public class TestTreeMap {
    @Test
    public void test1() {
        TreeMap<String,Integer> map = new TreeMap<>();
        map.put("Jack", 11000);
        map.put("Alice", 12000);
        map.put("zhangsan", 13000);
        map.put("baitao", 14000);
        map.put("Lucy", 15000);
        
        //String實現(xiàn)了Comparable接口,默認按照Unicode編碼值排序
        System.out.println(map);
    }
    @Test
    public void test2() {
        //指定定制比較器Comparator,按照Unicode編碼值排序,但是忽略大小寫
        TreeMap<String,Integer> map = new TreeMap<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareToIgnoreCase(o2);
            }
        });
        map.put("Jack", 11000);
        map.put("Alice", 12000);
        map.put("zhangsan", 13000);
        map.put("baitao", 14000);
        map.put("Lucy", 15000);
        
        System.out.println(map);
    }
}
```

#### **4、Properties**

Properties 類是 Hashtable 的子類,Properties 可保存在流中或從流中加載。屬性列表中每個鍵及其對應值都是一個字符串。

存取數(shù)據時,建議使用setProperty(String key,String value)方法和getProperty(String key)方法。

代碼示例:

```java
package com.atguigu.map;
import org.junit.Test;
import java.util.Properties;
public class TestProperties {
   @Test
   public void test01() {
       Properties properties = System.getProperties();
       String fileEncoding = properties.getProperty("file.encoding");//當前源文件字符編碼
       System.out.println("fileEncoding = " + fileEncoding);
   }
   @Test
   public void test02() {
       Properties properties = new Properties();
       properties.setProperty("user","chai");
       properties.setProperty("password","123456");
       System.out.println(properties);
   }
}
```

### 11.5.4 Set集合與Map集合的關系

Set的內部實現(xiàn)其實是一個Map。即HashSet的內部實現(xiàn)是一個HashMap,TreeSet的內部實現(xiàn)是一個TreeMap,LinkedHashSet的內部實現(xiàn)是一個LinkedHashMap。

部分源代碼摘要:

HashSet源碼:

```java
   public HashSet() {
       map = new HashMap<>();
   }
   public HashSet(Collection<? extends E> c) {
       map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
       addAll(c);
   }
   public HashSet(int initialCapacity, float loadFactor) {
       map = new HashMap<>(initialCapacity, loadFactor);
   }
   public HashSet(int initialCapacity) {
       map = new HashMap<>(initialCapacity);
   }
    //這個構造器是給子類LinkedHashSet調用的
   HashSet(int initialCapacity, float loadFactor, boolean dummy) {
       map = new LinkedHashMap<>(initialCapacity, loadFactor);
   }
```

LinkedHashSet源碼:

```java
   public LinkedHashSet(int initialCapacity, float loadFactor) {
       super(initialCapacity, loadFactor, true);//調用HashSet的某個構造器
   }
   public LinkedHashSet(int initialCapacity) {
       super(initialCapacity, .75f, true);//調用HashSet的某個構造器
   }
   public LinkedHashSet() {
       super(16, .75f, true);
   }
   public LinkedHashSet(Collection<? extends E> c) {
       super(Math.max(2*c.size(), 11), .75f, true);//調用HashSet的某個構造器
       addAll(c);
   }
```

TreeSet源碼:

```java
   public TreeSet() {
       this(new TreeMap<E,Object>());
   }
   public TreeSet(Comparator<? super E> comparator) {
       this(new TreeMap<>(comparator));
   }
   public TreeSet(Collection<? extends E> c) {
       this();
       addAll(c);
   }
   public TreeSet(SortedSet<E> s) {
       this(s.comparator());
       addAll(s);
   }
```

但是,咱們存到Set中只有一個元素,又是怎么變成(key,value)的呢?

以HashSet中的源碼為例:

```java
private static final Object PRESENT = new Object();
public boolean add(E e) {
   return map.put(e, PRESENT)==null;
}
public Iterator<E> iterator() {
   return map.keySet().iterator();
}
```

原來是,把添加到Set中的元素作為內部實現(xiàn)map的key,然后用一個常量對象PRESENT對象,作為value。

這是因為Set的元素不可重復和Map的key不可重復有相同特點。Map有一個方法keySet()可以返回所有key。

### 11.5.5 哈希表的原理分析

#### 1、二叉樹了解

二叉樹(Binary tree)是樹形結構的一個重要類型。二叉樹特點是每個結點最多只能有兩棵子樹,且有左右之分。許多實際問題抽象出來的數(shù)據結構往往是二叉樹形式,二叉樹的存儲結構及其算法都較為簡單,因此二叉樹顯得特別重要。

1574575739236-17028853496111.png

前序遍歷:ABDHIECFG

中序遍歷:HDIBEAFCG

后序遍歷:HIDEBFGCA

以下是幾種經典的二叉樹:

1、滿二叉樹: 除最后一層無任何子節(jié)點外,每一層上的所有結點都有兩個子結點的二叉樹。 第n層的結點數(shù)是2的n-1次方,總的結點個數(shù)是2的n次方-1

1574575163883-17028853496112.png

2、完全二叉樹: 葉結點只能出現(xiàn)在最底層的兩層,且最底層葉結點均處于次底層葉結點的左側。

1574575180247-17028853496113.png

3、平衡二叉樹:平衡二叉樹(Self-balancing binary search tree)又被稱為AVL樹(有別于AVL算法),且具有以下性質:它是一 棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,并且左右兩個子樹都是一棵平衡二叉樹, 但不要求非葉節(jié)點都有兩個子結點 。平衡二叉樹的常用實現(xiàn)方法有紅黑樹、AVL、替罪羊樹、Treap、伸展樹等。例如紅黑樹的要求:

- 節(jié)點是紅色或者黑色
- 根節(jié)點是黑色

- 每個葉子的節(jié)點都是黑色的空節(jié)點(NULL)

- 每個紅色節(jié)點的兩個子節(jié)點都是黑色的。

- 從任意節(jié)點到其每個葉子的所有路徑都包含相同的黑色節(jié)點數(shù)量。


當我們插入或刪除節(jié)點時,可能會破壞已有的紅黑樹,使得它不滿足以上5個要求,那么此時就需要進行處理:

1、recolor :將某個節(jié)點變紅或變黑

2、rotation :將紅黑樹某些結點分支進行旋轉(左旋或右旋)

使得它繼續(xù)滿足以上的5個要求。

紅黑樹-17028853496114.jpeg

例如:插入了結點21之后,紅黑樹處理成:

紅黑樹2-17028853496115.jpeg

 

#### 2、 哈希表的數(shù)據結構

請看PPT

## 11.6 集合框架

image-20240718161133558.png

 

## 11.7 Collections工具類

參考操作數(shù)組的工具類:Arrays。

Collections 是一個操作 Set、List 和 Map 等集合的工具類。Collections 中提供了一系列靜態(tài)的方法對集合元素進行排序、查詢和修改等操作,還提供了對集合對象設置不可變、對集合對象實現(xiàn)同步控制等方法:

* public static <T> boolean addAll(Collection<? super T> c,T... elements)將所有指定元素添加到指定 collection 中。
* public static <T> int binarySearch(List<? extends Comparable<? super T>> list,T key)在List集合中查找某個元素的下標,但是List的元素必須是T或T的子類對象,而且必須是可比較大小的,即支持自然排序的。而且集合也事先必須是有序的,否則結果不確定。
* public static <T> int binarySearch(List<? extends T> list,T key,Comparator<? super T> c)在List集合中查找某個元素的下標,但是List的元素必須是T或T的子類對象,而且集合也事先必須是按照c比較器規(guī)則進行排序過的,否則結果不確定。
* public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)在coll集合中找出最大的元素,集合中的對象必須是T或T的子類對象,而且支持自然排序
* public static <T> T max(Collection<? extends T> coll,Comparator<? super T> comp)在coll集合中找出最大的元素,集合中的對象必須是T或T的子類對象,按照比較器comp找出最大者
* public static void reverse(List<?> list)反轉指定列表List中元素的順序。
* public static void shuffle(List<?> list) List 集合元素進行隨機排序,類似洗牌
* public static <T extends Comparable<? super T>> void sort(List<T> list)根據元素的自然順序對指定 List 集合元素按升序排序
* public static <T> void sort(List<T> list,Comparator<? super T> c)根據指定的 Comparator 產生的順序對 List 集合元素進行排序
* public static void swap(List<?> list,int i,int j)將指定 list 集合中的 i 處元素和 j 處元素進行交換
* public static int frequency(Collection<?> c,Object o)返回指定集合中指定元素的出現(xiàn)次數(shù)
* public static <T> void copy(List<? super T> dest,List<? extends T> src)將src中的內容復制到dest中
* public static <T> boolean replaceAll(List<T> list,T oldVal,T newVal):使用新值替換 List 對象的所有舊值
* Collections 類中提供了多個 synchronizedXxx() 方法,該方法可使將指定集合包裝成線程同步的集合,從而可以解決多線程并發(fā)訪問集合時的線程安全問題
* Collections類中提供了多個unmodifiableXxx()方法,該方法返回指定 Xxx的不可修改的視圖。

```java
package com.atguigu.collections;
import org.junit.Test;
import java.text.Collator;
import java.util.*;
public class TestCollections {
   @Test
   public void test11(){
       /*
       public static <T> boolean replaceAll(List<T> list,T oldVal,T newVal):使用新值替換 List 對象的所有舊值
        */
       List<String> list = new ArrayList<>();
       Collections.addAll(list,"hello","java","world","hello","hello");
       Collections.replaceAll(list, "hello","chai");
       System.out.println(list);
   }
   @Test
   public void test10(){
       List<Integer> list = new ArrayList<>();
       for(int i=1; i<=5; i++){//1-5
           list.add(i);
       }
       List<Integer> list2 = new ArrayList<>();
       for(int i=11; i<=13; i++){//11-13
           list2.add(i);
       }
       list.addAll(list2);
       System.out.println(list);//[1, 2, 3, 4, 5, 11, 12, 13]
   }
   @Test
   public void test09(){
       /*
        * public static <T> void copy(List<? super T> dest,List<? extends T> src)將src中的內容復制到dest中
        */
       List<Integer> list = new ArrayList<>();
       for(int i=1; i<=5; i++){//1-5
           list.add(i);
       }
       List<Integer> list2 = new ArrayList<>();
       for(int i=11; i<=13; i++){//11-13
           list2.add(i);
       }
       Collections.copy(list, list2);
       System.out.println(list);
       List<Integer> list3 = new ArrayList<>();
       for(int i=11; i<=20; i++){//11-20
           list3.add(i);
       }
       Collections.copy(list, list3);//java.lang.IndexOutOfBoundsException: Source does not fit in dest
       System.out.println(list);
   }
   @Test
   public void test08(){
       /*
       public static int frequency(Collection<?> c,Object o)返回指定集合中指定元素的出現(xiàn)次數(shù)
        */
       List<String> list = new ArrayList<>();
       Collections.addAll(list,"hello","java","world","hello","hello");
       int count = Collections.frequency(list, "hello");
       System.out.println("count = " + count);
   }
   @Test
   public void test07(){
       /*
       public static void swap(List<?> list,int i,int j)將指定 list 集合中的 i 處元素和 j 處元素進行交換
        */
       List<String> list = new ArrayList<>();
       Collections.addAll(list,"hello","java","world");
       Collections.swap(list,0,2);
       System.out.println(list);
   }
   @Test
   public void test06() {
       /*
        * public static <T extends Comparable<? super T>> void sort(List<T> list)根據元素的自然順序對指定 List 集合元素按升序排序
        * public static <T> void sort(List<T> list,Comparator<? super T> c)根據指定的 Comparator 產生的順序對 List 集合元素進行排序
        */
       List<Man> list = new ArrayList<>();
       list.add(new Man("張三",23));
       list.add(new Man("李四",24));
       list.add(new Man("王五",25));
       Collections.sort(list);
       System.out.println(list);
       Collections.sort(list, new Comparator<Man>() {
           @Override
           public int compare(Man o1, Man o2) {
               return Collator.getInstance(Locale.CHINA).compare(o1.getName(),o2.getName());
           }
       });
       System.out.println(list);
   }
   @Test
   public void test05(){
       /*
       public static void shuffle(List<?> list) List 集合元素進行隨機排序,類似洗牌,打亂順序
        */
       List<String> list = new ArrayList<>();
       Collections.addAll(list,"hello","java","world");
       Collections.shuffle(list);
       System.out.println(list);
   }
   @Test
   public void test04(){
       /*
       public static void reverse(List<?> list)反轉指定列表List中元素的順序。
        */
       List<String> list = new ArrayList<>();
       Collections.addAll(list,"hello","java","world");
       System.out.println(list);
       Collections.reverse(list);
       System.out.println(list);
   }
   @Test
   public void test03(){
       /*
        * public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
        *      <T extends Object & Comparable<? super T>>:要求T必須繼承Object,又實現(xiàn)Comparable接口,或者T的父類實現(xiàn)Comparable接口
        *      在coll集合中找出最大的元素,集合中的對象必須是T或T的子類對象,而且支持自然排序
        * public static <T> T max(Collection<? extends T> coll,Comparator<? super T> comp)
        *      在coll集合中找出最大的元素,集合中的對象必須是T或T的子類對象,按照比較器comp找出最大者
        *
        */
       List<Man> list = new ArrayList<>();
       list.add(new Man("張三",23));
       list.add(new Man("李四",24));
       list.add(new Man("王五",25));
       /*Man max = Collections.max(list);//要求Man實現(xiàn)Comparable接口,或者父類實現(xiàn)
       System.out.println(max);*/
       Man max = Collections.max(list, new Comparator<Man>() {
           @Override
           public int compare(Man o1, Man o2) {
               return o2.getAge()-o2.getAge();
           }
       });
       System.out.println(max);
   }
   @Test
   public void test02(){
       /*
        * public static <T> int binarySearch(List<? extends Comparable<? super T>> list,T key)
        *      要求List集合的元素類型 實現(xiàn)了 Comparable接口,這個實現(xiàn)可以是T類型本身也可以T的父類實現(xiàn)這個接口。
        *      說明List中的元素支持自然排序功能。
        *      在List集合中查找某個元素的下標,但是List的元素必須是T或T的子類對象,而且必須是可比較大小的,即支持自然排序的。而且集合也事先必須是有序的,否則結果不確定。
        * public static <T> int binarySearch(List<? extends T> list,T key,Comparator<? super T> c)
        *      說明List集合中元素的類型<=T,Comparator<? super T>說明要傳入一個Comparator接口的實現(xiàn)類對象,實現(xiàn)類泛型的指定要求>=T
        *      例如:List中存儲的是Man(男)對象,T可以是Person類型,實現(xiàn)Comparator的時候可以是 Comparator<Person>
        *      例如:List中存儲的是Man(男)對象,T可以是Man類型,實現(xiàn)Comparator的時候可以是 Comparator<Person>
        *     在List集合中查找某個元素的下標,但是List的元素必須是T或T的子類對象,而且集合也事先必須是按照c比較器規(guī)則進行排序過的,否則結果不確定。
        *
        * 二分查找要求數(shù)組或List必須是“有大小順序”。
        * 二分查找的思路: 和[mid]元素比較,如果相同,就找到了,不相同要看大小關系,決定去左邊還是右邊繼續(xù)查找。
        */
       List<Man> list = new ArrayList<>();
       list.add(new Man("張三",23));
       list.add(new Man("李四",24));
       list.add(new Man("王五",25));
//        int index = Collections.binarySearch(list, new Man("王五", 25));//要求實現(xiàn)Comparable接口
//        System.out.println(index);
       int index = Collections.binarySearch(list, new Man("王五", 25), new Comparator<Person>() {
           @Override
           public int compare(Person o1, Person o2) {
               return o1.getAge() - o2.getAge();
           }
       });
       System.out.println(index);
   }
   @Test
   public void test01(){
       /*
       public static <T> boolean addAll(Collection<? super T> c,T... elements)將所有指定元素添加到指定 collection 中。
       Collection的集合的元素類型必須>=T類型
        */
       Collection<Object> coll = new ArrayList<>();
       Collections.addAll(coll, "hello","java");
       Collections.addAll(coll, 1,2,3,4);
       Collection<String> coll2 = new ArrayList<>();
       Collections.addAll(coll2, "hello","java");
//        Collections.addAll(coll2, 1,2,3,4);//String和Integer之間沒有父子類關系
   }
}
```

## 11.8 Arrays工具類

public static <T> List<T> asList(T... a):將指定元素添加到一個固定大小的列表中,并返回列表。

```java
@Test
   public void test(){
       List<String> list = Arrays.asList("hello", "java", "world");
       System.out.println(list);
       try {
           list.add("chai");
       } catch (Exception e) {
           e.printStackTrace();
       }
       try {
           list.remove("hello");
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
```