十三:集合

提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔

文章目錄

  • 01、Java 集合框架概述
    • 1.1、集合框架與數組的對比及概述
    • 1.2、集合框架涉及到的API
  • 02、Collection接口方法
    • 2.1、Collection接口中的常用方法1
    • 2.2、Collection接口中的常用方法2
    • 2.3、Collection接口中的常用方法3
    • 2.4、Collection接口中的常用方法4
  • 03、Iterator迭代器接口
    • 3.1、使用Iterator遍歷Collection
    • 3.2、迭代器Iterator的執行原理
    • 3.3、Iterator遍歷集合的兩種錯誤寫法
    • 3.4、Iterator迭代器remove()的使用
    • 3.5、新特性foreach循環遍歷集合或數組
  • 04、Collection子接口之一:List接口
    • 4.1、List接口常用實現類的對比
    • 4.2、ArrayList的源碼分析
    • 4.3、LinkedList的源碼分析
    • 4.4、Vector的源碼分析
    • 4.5、List接口中的常用方法測試
    • 4.6、List的一個面試小題
  • 05、Collection子接口之二:Set接口
    • 5.1、Set接口實現類的對比
    • 5.2、Set的無序性與不可重復性的理解
    • 5.3、HashSet中元素的添加過程
    • 5.4、關于hashCode()和equals()的重寫
      • 5.4.1、重寫hashCode() 方法的基本原則
      • 5.4.2、重寫equals() 方法的基本原則
      • 5.4.3、Eclipse/IDEA工具里hashCode()的重寫
    • 5.5、LinkedHashSet的使用
    • 5.6、TreeSet的自然排序
    • 5.7、TreeSet的定制排序
    • 5.8、TreeSet的課后練習
    • 5.9、Set課后兩道面試題
  • 06、Map接口
    • 6.1、Map接口及其多個實現類的對比
    • 6.2、Map中存儲的key-value的特點
    • 6.3、Map實現類之一:HashMap
    • 6.4、HashMap的底層實現原理
    • 6.4.1、HashMap在JDK7中的底層實現原理
      • 6.4.2、HashMap在JDK8中的底層實現原理
    • 6.7、LinkedHashMap的底層實現原理(了解)
    • 6.8、Map中的常用方法1
    • 6.9、Map中的常用方法2
    • 6.10、TreeMap兩種添加方式的使用
    • 6.12、Hashtable
    • 6.13、Properties處理屬性文件
  • 07、Collections工具類
    • 7.1、Collections工具類常用方法的測試


01、Java 集合框架概述

1.1、集合框架與數組的對比及概述

/*** 一、集合的框架** 1.集合、數組都是對多個數據進行存儲操作的結構,簡稱Java容器。*   說明;此時的存儲,主要是指能存層面的存儲,不涉及到持久化的存儲(.txt,.jpg,.avi,數據庫中)** 2.1數組在存儲多個數據封面的特點:*      》一旦初始化以后,它的長度就確定了。*      》數組一旦定義好,它的數據類型也就確定了。我們就只能操作指定類型的數據了。*      比如:String[] arr;int[] str;* 2.2數組在存儲多個數據方面的特點:*      》一旦初始化以后,其長度就不可修改。*      》數組中提供的方法非常有限,對于添加、刪除、插入數據等操作,非常不便,同時效率不高。*      》獲取數組中實際元素的個數的需求,數組沒有現成的屬性或方法可用*      》數組存儲數據的特點:有序、可重復。對于無序、不可重復的需求,不能滿足。**/

1.2、集合框架涉及到的API

  • Java 集合可分為Collection 和Map 兩種體系
    • Collection接口:單列數據,定義了存取一組對象的方法的集合
      • List:元素有序、可重復的集合
      • Set:元素無序、不可重復的集合
    • Map接口:雙列數據,保存具有映射關系“key-value對”的集合

1、Collection接口繼承樹
在這里插入圖片描述

2、Map接口繼承樹

在這里插入圖片描述

/**** 二、集合框架*      &---Collection接口:單列集合,用來存儲一個一個的對象*          &---List接口:存儲有序的、可重復的數據。  -->“動態”數組*              &---ArrayList、LinkedList、Vector**          &---Set接口:存儲無序的、不可重復的數據   -->高中講的“集合”*              &---HashSet、LinkedHashSet、TreeSet**      &---Map接口:雙列集合,用來存儲一對(key - value)一對的數據   -->高中函數:y = f(x)*          &---HashMap、LinkedHashMap、TreeMap、Hashtable、Properties**/

02、Collection接口方法

  • Collection 接口是List、Set 和Queue 接口的父接口,該接口里定義的方法既可用于操作Set 集合,也可用于操作List 和Queue 集合。
  • JDK不提供此接口的任何直接實現,而是提供更具體的子接口(如:Set和List)實現。
  • 在Java5 之前,Java 集合會丟失容器中所有對象的數據類型,把所有對象都當成Object 類型處理;從JDK 5.0 增加了泛型以后,Java 集合可以記住容器中對象的數據類型。

2.1、Collection接口中的常用方法1

  1. 添加
    • add(Objec tobj)
    • addAll(Collection coll)
  2. 獲取有效元素的個數
    • int size()
  3. 清空集合
    • void clear()
  4. 是否是空集合
    • boolean isEmpty()
  5. 是否包含某個元素
    • boolean contains(Object obj):是通過元素的equals方法來判斷是否是同一個對象
    • boolean containsAll(Collection c):也是調用元素的equals方法來比較的。拿兩個集合的元素挨個比較。
  6. 刪除
    • boolean remove(Object obj) :通過元素的equals方法判斷是否是要刪除的那個元素。只會刪除找到的第一個元素
    • boolean removeAll(Collection coll):取當前集合的差集
  7. 取兩個集合的交集
    • boolean retainAll(Collection c):把交集的結果存在當前集合中,不影響c
  8. 集合是否相等
    • boolean equals(Object obj)
  9. 轉成對象數組
    • Object[] toArray()
  10. 獲取集合對象的哈希值
    • hashCode()
  11. 遍歷
    • iterator():返回迭代器對象,用于集合遍歷
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;/**** 三、Collection接口中的方法的使用**/
public class CollectionTest {@Testpublic void test1(){Collection coll = new ArrayList();//add(Object e):將元素e添加到集合coll中coll.add("AA");coll.add("BB");coll.add(123);  //自動裝箱coll.add(new Date());//size():獲取添加的元素的個數System.out.println(coll.size());    //4//addAll(Collection coll1):將coll1集合中的元素添加到當前的集合中Collection coll1 = new ArrayList();coll1.add(456);coll1.add("CC");coll.addAll(coll1);System.out.println(coll.size());    //6System.out.println(coll);//clear():清空集合元素coll.clear();//isEmpty():判斷當前集合是否為空System.out.println(coll.isEmpty());}
}

2.2、Collection接口中的常用方法2

1、Person類

import java.util.Objects;public class Person {private String name;private int age;public Person() {super();}public Person(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;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {System.out.println("Person equals()....");if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return age == person.age &&Objects.equals(name, person.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}
}

2、測試類

import org.junit.Test;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;/*** Collection接口中聲明的方法的測試** 結論:* 向Collection接口的實現類的對象中添加數據obj時,要求obj所在類要重寫equals().*/
public class CollectinoTest {@Testpublic void test(){Collection coll = new ArrayList();coll.add(123);coll.add(456);//        Person p = new Person("Jerry",20);
//        coll.add(p);coll.add(new Person("Jerry",20));coll.add(new String("Tom"));coll.add(false);//1.contains(Object obj):判斷當前集合中是否包含obj//我們在判斷時會調用obj對象所在類的equals()。boolean contains = coll.contains(123);System.out.println(contains);System.out.println(coll.contains(new String("Tam")));
//        System.out.println(coll.contains(p));//trueSystem.out.println(coll.contains(new Person("Jerry",20)));//false -->true//2.containsAll(Collection coll1):判斷形參coll1中的所有元素是否都存在于當前集合中。Collection coll1 = Arrays.asList(123,4567);System.out.println(coll.containsAll(coll1));}}

2.3、Collection接口中的常用方法3

1、Person類

import java.util.Objects;public class Person {private String name;private int age;public Person() {super();}public Person(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;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {System.out.println("Person equals()....");if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return age == person.age &&Objects.equals(name, person.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}
}

2、測試類

import org.junit.Test;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;/*** Collection接口中聲明的方法的測試** 結論:* 向Collection接口的實現類的對象中添加數據obj時,要求obj所在類要重寫equals().**/
public class CollectinoTest {@Testpublic void test2(){//3.remove(Object obj):從當前集合中移除obj元素。Collection coll = new ArrayList();coll.add(123);coll.add(456);coll.add(new Person("Jerry",20));coll.add(new String("Tom"));coll.add(false);coll.remove(1234);System.out.println(coll);coll.remove(new Person("Jerry",20));System.out.println(coll);//4. removeAll(Collection coll1):差集:從當前集合中移除coll1中所有的元素。Collection coll1 = Arrays.asList(123,456);coll.removeAll(coll1);System.out.println(coll);}@Testpublic void test3(){Collection coll = new ArrayList();coll.add(123);coll.add(456);coll.add(new Person("Jerry",20));coll.add(new String("Tom"));coll.add(false);//5.retainAll(Collection coll1):交集:獲取當前集合和coll1集合的交集,并返回給當前集合
//        Collection coll1 = Arrays.asList(123,456,789);
//        coll.retainAll(coll1);
//        System.out.println(coll);//6.equals(Object obj):要想返回true,需要當前集合和形參集合的元素都相同。Collection coll1 = new ArrayList();coll1.add(456);coll1.add(123);coll1.add(new Person("Jerry",20));coll1.add(new String("Tom"));coll1.add(false);System.out.println(coll.equals(coll1));}}

2.4、Collection接口中的常用方法4

1、Person類

import java.util.Objects;public class Person {private String name;private int age;public Person() {super();}public Person(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;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {System.out.println("Person equals()....");if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return age == person.age &&Objects.equals(name, person.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}
}
import org.junit.Test;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;/*** Collection接口中聲明的方法的測試** 結論:* 向Collection接口的實現類的對象中添加數據obj時,要求obj所在類要重寫equals().**/
public class CollectinoTest {@Testpublic void test4(){Collection coll = new ArrayList();coll.add(123);coll.add(456);coll.add(new Person("Jerry",20));coll.add(new String("Tom"));coll.add(false);//7.hashCode():返回當前對象的哈希值System.out.println(coll.hashCode());//8.集合 --->數組:toArray()Object[] arr = coll.toArray();for(int i = 0;i < arr.length;i++){System.out.println(arr[i]);}//拓展:數組 --->集合:調用Arrays類的靜態方法asList()List<String> list = Arrays.asList(new String[]{"AA", "BB", "CC"});System.out.println(list);List arr1 = Arrays.asList(123, 456);System.out.println(arr1);//[123, 456]List arr2 = Arrays.asList(new int[]{123, 456});System.out.println(arr2.size());//1List arr3 = Arrays.asList(new Integer[]{123, 456});System.out.println(arr3.size());//2//9.iterator():返回Iterator接口的實例,用于遍歷集合元素。放在IteratorTest.java中測試}
}

03、Iterator迭代器接口

  • Iterator對象稱為迭代器(設計模式的一種),主要用于遍歷Collection 集合中的元素。
  • GOF給迭代器模式的定義為:提供一種方法訪問一個容器(container)對象中各個元素,而又不需暴露該對象的內部細節。迭代器模式,就是為容器而生。類似于“公交車上的售票員”、“火車上的乘務員”、“空姐”。
  • Collection接口繼承了java.lang.Iterable接口,該接口有一個iterator()方法,那么所有實現了Collection接口的集合類都有一個iterator()方法,用以返回一個實現了Iterator接口的對象。
  • Iterator 僅用于遍歷集合,Iterator本身并不提供承裝對象的能力。如果需要創建Iterator 對象,則必須有一個被迭代的集合。
  • 集合對象每次調用iterator()方法都得到一個全新的迭代器對象,默認游標都在集合的第一個元素之前。
    在這里插入圖片描述

3.1、使用Iterator遍歷Collection

import org.junit.Test;import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;/*** 集合元素的遍歷操作,使用迭代器Iterator接口* 內部的方法:hasNext()和 next()**/
public class IteratorTest {@Testpublic void test(){Collection coll = new ArrayList();coll.add(123);coll.add(456);coll.add(new Person("Jerry",20));coll.add(new String("Tom"));coll.add(false);Iterator iterator = coll.iterator();//方式一:
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
//        //報異常:NoSuchElementException
//        //因為:在調用it.next()方法之前必須要調用it.hasNext()進行檢測。若不調用,且下一條記錄無效,直接調用it.next()會拋出NoSuchElementException異常。
//        System.out.println(iterator.next());//方式二:不推薦
//        for(int i = 0;i < coll.size();i++){
//            System.out.println(iterator.next());
//        }//方式三:推薦while(iterator.hasNext()){System.out.println(iterator.next());}}
}

3.2、迭代器Iterator的執行原理

在這里插入圖片描述

3.3、Iterator遍歷集合的兩種錯誤寫法

import org.junit.Test;import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;/*** 集合元素的遍歷操作,使用迭代器Iterator接口* 1.內部的方法:hasNext()和 next()* 2.集合對象每次調用iterator()方法都得到一個全新的迭代器對象,默認游標都在集合的第一個元素之前。*/
public class IteratorTest {@Testpublic void test2(){Collection coll = new ArrayList();coll.add(123);coll.add(456);coll.add(new Person("Jerry",20));coll.add(new String("Tom"));coll.add(false);//錯誤方式一:
//        Iterator iterator = coll.iterator();
//        while(iterator.next() != null){
//            System.out.println(iterator.next());
//        }//錯誤方式二://集合對象每次調用iterator()方法都得到一個全新的迭代器對象,默認游標都在集合的第一個元素之前。while(coll.iterator().hasNext()){System.out.println(coll.iterator().next());}}
}

3.4、Iterator迭代器remove()的使用

import org.junit.Test;import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;/*** 集合元素的遍歷操作,使用迭代器Iterator接口* 1.內部的方法:hasNext()和 next()* 2.集合對象每次調用iterator()方法都得到一個全新的迭代器對象,默認游標都在集合的第一個元素之前。* 3.內部定義了remove(),可以在遍歷的時候,刪除集合中的元素。此方法不同于集合直接調用remove()*/
public class IteratorTest {//測試Iterator中的remove()方法@Testpublic void test3(){Collection coll = new ArrayList();coll.add(123);coll.add(456);coll.add(new Person("Jerry",20));coll.add(new String("Tom"));coll.add(false);//刪除集合中”Tom”//如果還未調用next()或在上一次調用 next 方法之后已經調用了 remove 方法,// 再調用remove都會報IllegalStateException。Iterator iterator = coll.iterator();while(iterator.hasNext()){
//            iterator.remove();Object obj = iterator.next();if("Tom".equals(obj)){iterator.remove();
//                iterator.remove();                }}//遍歷集合iterator = coll.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}}
}

注意:

  • Iterator可以刪除集合的元素,但是是遍歷過程中通過迭代器對象的remove方法,不是集合對象的remove方法。
  • 如果還未調用next()或在上一次調用next方法之后已經調用了remove方法,再調用remove都會報IllegalStateException。

3.5、新特性foreach循環遍歷集合或數組

  • Java 5.0 提供了foreach循環迭代訪問Collection和數組。
  • 遍歷操作不需獲取Collection或數組的長度,無需使用索引訪問元素。
  • 遍歷集合的底層調用Iterator完成操作。
  • foreach還可以用來遍歷數組。

在這里插入圖片描述

import org.junit.Test;import java.util.ArrayList;
import java.util.Collection;/*** jdk 5.0 新增了foreach循環,用于遍歷集合、數組**/
public class ForTest {@Testpublic void test(){Collection coll = new ArrayList();coll.add(123);coll.add(456);coll.add(new Person("Jerry",20));coll.add(new String("Tom"));coll.add(false);//for(集合元素的類型 局部變量 : 集合對象),內部仍然調用了迭代器。for(Object obj : coll){System.out.println(obj);}}@Testpublic void test2(){int[] arr = new int[]{1,2,3,4,5,6};//for(數組元素的類型 局部變量 : 數組對象)for(int i : arr){System.out.println(i);}}//練習題@Testpublic void test3(){String[] arr = new String[]{"SS","KK","RR"};//        //方式一:普通for賦值
//        for(int i = 0;i < arr.length;i++){
//            arr[i] = "HH";
//        }//方式二:增強for循環for(String s : arr){s = "HH";}for(int i = 0;i < arr.length;i++){System.out.println(arr[i]);}}
}

04、Collection子接口之一:List接口

  • 鑒于Java中數組用來存儲數據的局限性,我們通常使用List替代數組
  • List集合類中元素有序、且可重復,集合中的每個元素都有其對應的順序索引。
  • List容器中的元素都對應一個整數型的序號記載其在容器中的位置,可以根據序號存取容器中的元素。
  • JDK API中List接口的實現類常用的有:ArrayList、LinkedList和Vector。

4.1、List接口常用實現類的對比

/*** 1. List接口框架**    |----Collection接口:單列集合,用來存儲一個一個的對象*          |----List接口:存儲有序的、可重復的數據。  -->“動態”數組,替換原有的數組*              |----ArrayList:作為List接口的主要實現類;線程不安全的,效率高;底層使用Object[] elementData存儲*              |----LinkedList:對于頻繁的插入、刪除操作,使用此類效率比ArrayList高;底層使用雙向鏈表存儲*              |----Vector:作為List接口的古老實現類;線程安全的,效率低;底層使用Object[] elementData存儲*** 面試題:比較ArrayList、LinkedList、Vector三者的異同?*        同:三個類都是實現了List接口,存儲數據的特點相同:存儲有序的、可重復的數據*        不同:見上**/

4.2、ArrayList的源碼分析

  • ArrayList是List 接口的典型實現類、主要實現類
  • 本質上,ArrayList是對象引用的一個”變長”數組
/** * 2.ArrayList的源碼分析:*   2.1 jdk 7情況下*      ArrayList list = new ArrayList();//底層創建了長度是10的Object[]數組elementData*      list.add(123);//elementData[0] = new Integer(123);*      ...*      list.add(11);//如果此次的添加導致底層elementData數組容量不夠,則擴容。*      默認情況下,擴容為原來的容量的1.5倍,同時需要將原有數組中的數據復制到新的數組中。**      結論:建議開發中使用帶參的構造器:ArrayList list = new ArrayList(int capacity)**   2.2 jdk 8中ArrayList的變化:*      ArrayList list = new ArrayList();//底層Object[] elementData初始化為{}.并沒有創建長度為10的數組**      list.add(123);//第一次調用add()時,底層才創建了長度10的數組,并將數據123添加到elementData[0]*      ...*      后續的添加和擴容操作與jdk 7 無異。*   2.3 小結:jdk7中的ArrayList的對象的創建類似于單例的餓漢式,而jdk8中的ArrayList的對象*            的創建類似于單例的懶漢式,延遲了數組的創建,節省內存。* */

4.3、LinkedList的源碼分析

  • 對于頻繁的插入或刪除元素的操作,建議使用LinkedList類,效率較高
  • LinkedList:雙向鏈表,內部沒有聲明數組,而是定義了Node類型的first和last,用于記錄首末元素。同時,定義內部類Node,作為LinkedList中保存數據的基本結構。

在這里插入圖片描述

/*** 3.LinkedList的源碼分析:*       LinkedList list = new LinkedList(); 內部聲明了Node類型的first和last屬性,默認值為null*       list.add(123);//將123封裝到Node中,創建了Node對象。**       其中,Node定義為:體現了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;     //next變量記錄下一個元素的位置*            this.prev = prev;     //prev變量記錄前一個元素的位置*            }*        }*/

4.4、Vector的源碼分析

  • Vector 是一個古老的集合,JDK1.0就有了。大多數操作與ArrayList相同,區別之處在于Vector是線程安全的。
  • 在各種list中,最好把ArrayList作為缺省選擇。當插入、刪除頻繁時,使用LinkedList;Vector總是比ArrayList慢,所以盡量避免使用。
/** * 4.Vector的源碼分析:jdk7和jdk8中通過Vector()構造器創建對象時,底層都創建了長度為10的數組。*      在擴容方面,默認擴容為原來的數組長度的2倍。*/ 

4.5、List接口中的常用方法測試

List除了從Collection集合繼承的方法外,List 集合里添加了一些根據索引來操作集合元素的方法。

  • void add(intindex, 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位置的子集合
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;/**** 5.List接口的常用方法*/
public class ListTest {/**** 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位置的子集合** 總結:常用方法* 增:add(Object obj)* 刪:remove(int index) / remove(Object obj)* 改:set(int index, Object ele)* 查:get(int index)* 插:add(int index, Object ele)* 長度:size()* 遍歷:① Iterator迭代器方式*      ② 增強for循環*      ③ 普通的循環**/@Testpublic void test3(){ArrayList list = new ArrayList();list.add(123);list.add(456);list.add("AA");//方式一:Iterator迭代器方式Iterator iterator = list.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}System.out.println("***************");//方式二:增強for循環for(Object obj : list){System.out.println(obj);}System.out.println("***************");//方式三:普通for循環for(int i = 0;i < list.size();i++){System.out.println(list.get(i));}}@Testpublic void tets2(){ArrayList list = new ArrayList();list.add(123);list.add(456);list.add("AA");list.add(new Person("Tom",12));list.add(456);//int indexOf(Object obj):返回obj在集合中首次出現的位置。如果不存在,返回-1.int index = list.indexOf(4567);System.out.println(index);//int lastIndexOf(Object obj):返回obj在當前集合中末次出現的位置。如果不存在,返回-1.System.out.println(list.lastIndexOf(456));//Object remove(int index):移除指定index位置的元素,并返回此元素Object obj = list.remove(0);System.out.println(obj);System.out.println(list);//Object set(int index, Object ele):設置指定index位置的元素為elelist.set(1,"CC");System.out.println(list);//List subList(int fromIndex, int toIndex):返回從fromIndex到toIndex位置的左閉右開區間的子集合List subList = list.subList(2, 4);System.out.println(subList);System.out.println(list);}@Testpublic void test(){ArrayList list = new ArrayList();list.add(123);list.add(456);list.add("AA");list.add(new Person("Tom",12));list.add(456);System.out.println(list);//void add(int index, Object ele):在index位置插入ele元素list.add(1,"BB");System.out.println(list);//boolean addAll(int index, Collection eles):從index位置開始將eles中的所有元素添加進來List list1 = Arrays.asList(1, 2, 3);list.addAll(list1);
//        list.add(list1);System.out.println(list.size());//9//Object get(int index):獲取指定index位置的元素System.out.println(list.get(2));}
}

4.6、List的一個面試小題

1、面試題1

請問ArrayList/LinkedList/Vector的異同?談談你的理解?ArrayList底層是什么?擴容機制?Vector和ArrayList的最大區別?

   /*** 請問ArrayList/LinkedList/Vector的異同?談談你的理解?* ArrayList底層是什么?擴容機制?Vector和ArrayList的最大區別?* * ArrayList和LinkedList的異同二者都線程不安全,相對線程安全的Vector,執行效率高。* 此外,ArrayList是實現了基于動態數組的數據結構,LinkedList基于鏈表的數據結構。* 對于隨機訪問get和set,ArrayList覺得優于LinkedList,因為LinkedList要移動指針。* 對于新增和刪除操作add(特指插入)和remove,LinkedList比較占優勢,因為ArrayList要移動數據。* * ArrayList和Vector的區別Vector和ArrayList幾乎是完全相同的,* 唯一的區別在于Vector是同步類(synchronized),屬于強同步類。* 因此開銷就比ArrayList要大,訪問要慢。正常情況下,* 大多數的Java程序員使用ArrayList而不是Vector,* 因為同步完全可以由程序員自己來控制。Vector每次擴容請求其大小的2倍空間,* 而ArrayList是1.5倍。Vector還有一個子類Stack。*/

2、面試題2

import org.junit.Test;import java.util.ArrayList;
import java.util.List;public class ListEver {/*** 區分List中remove(int index)和remove(Object obj)*/@Testpublic void testListRemove() {List list = new ArrayList();list.add(1);list.add(2);list.add(3);updateList(list);System.out.println(list);//}private void updateList(List list) {
//        list.remove(2);list.remove(new Integer(2));}
}

05、Collection子接口之二:Set接口

  • Set接口是Collection的子接口,set接口沒有提供額外的方法
  • Set 集合不允許包含相同的元素,如果試把兩個相同的元素加入同一個Set 集合中,則添加操作失敗。
  • Set 判斷兩個對象是否相同不是使用== 運算符,而是根據equals() 方法

5.1、Set接口實現類的對比

/*** 1.Set接口的框架:* |----Collection接口:單列集合,用來存儲一個一個的對象*          |----Set接口:存儲無序的、不可重復的數據   -->高中講的“集合”*             |----HashSet:作為Set接口的主要實現類;線程不安全的;可以存儲null值*                 |----LinkedHashSet:作為HashSet的子類;遍歷其內部數據時,可以按照添加的順序遍歷*                                    對于頻繁的遍歷操作,LinkedHashSet效率高于HashSet.*             |----TreeSet:可以按照添加對象的指定屬性,進行排序。*/

5.2、Set的無序性與不可重復性的理解

1、測試類

import org.junit.Test;import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;/**** 1.Set接口中沒有定義額外的方法,使用的都是Collection中聲明過的方法。**/
public class SetTest {/*** 一、Set:存儲無序的、不可重復的數據*      1.無序性:不等于隨機性。存儲的數據在底層數組中并非按照數組索引的順序添加,而是根據數據的哈希值決定的。**      2.不可重復性:保證添加的元素按照equals()判斷時,不能返回true.即:相同的元素只能添加一個。** 二、添加元素的過程:以HashSet為例:***/@Testpublic void test(){Set set = new HashSet();set.add(123);set.add(456);set.add("fgd");set.add("book");set.add(new User("Tom",12));set.add(new User("Tom",12));set.add(129);Iterator iterator = set.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}}
}

2、User類

public class User{private String name;private int age;public User() {}public User(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;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {System.out.println("User equals()....");if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;User user = (User) o;if (age != user.age) return false;return name != null ? name.equals(user.name) : user.name == null;}@Overridepublic int hashCode() { int result = name != null ? name.hashCode() : 0;result = 31 * result + age;return result;}
}

5.3、HashSet中元素的添加過程

  • HashSet是Set 接口的典型實現,大多數時候使用Set 集合時都使用這個實現類。
  • HashSet按Hash 算法來存儲集合中的元素,因此具有很好的存取、查找、刪除性能。
  • HashSet具有以下特點:不能保證元素的排列順序
    • HashSet不是線程安全的
    • 集合元素可以是null
  • 底層也是數組,初始容量為16,當如果使用率超過0.75,(16*0.75=12)就會擴大容量為原來的2倍。(16擴容為32,依次為64,128…等)
  • HashSet 集合判斷兩個元素相等的標準:兩個對象通過hashCode() 方法比較相等,并且兩個對象的equals() 方法返回值也相等。
  • 對于存放在Set容器中的對象,對應的類一定要重寫equals()和hashCode(Object obj)方法,以實現對象相等規則。即:“相等的對象必須具有相等的散列碼”。
/*** 一、Set:存儲無序的、不可重復的數據*      1.無序性:不等于隨機性。存儲的數據在底層數組中并非按照數組索引的順序添加,而是根據數據的哈希值決定的。**      2.不可重復性:保證添加的元素按照equals()判斷時,不能返回true.即:相同的元素只能添加一個。** 二、添加元素的過程:以HashSet為例:*      我們向HashSet中添加元素a,首先調用元素a所在類的hashCode()方法,計算元素a的哈希值,*      此哈希值接著通過某種算法計算出在HashSet底層數組中的存放位置(即為:索引位置),判斷*      數組此位置上是否已經有元素:*          如果此位置上沒有其他元素,則元素a添加成功。 --->情況1*          如果此位置上有其他元素b(或以鏈表形式存在的多個元素),則比較元素a與元素b的hash值:*              如果hash值不相同,則元素a添加成功。--->情況2*              如果hash值相同,進而需要調用元素a所在類的equals()方法:*                    equals()返回true,元素a添加失敗*                    equals()返回false,則元素a添加成功。--->情況2**      對于添加成功的情況2和情況3而言:元素a 與已經存在指定索引位置上數據以鏈表的方式存儲。*      jdk 7 :元素a放到數組中,指向原來的元素。*      jdk 8 :原來的元素在數組中,指向元素a*      總結:七上八下** HashSet底層:數組+鏈表的結構。**/

在這里插入圖片描述

5.4、關于hashCode()和equals()的重寫

5.4.1、重寫hashCode() 方法的基本原則

  • 在程序運行時,同一個對象多次調用hashCode() 方法應該返回相同的值。
  • 當兩個對象的equals() 方法比較返回true 時,這兩個對象的hashCode() 方法的返回值也應相等。
  • 對象中用作equals() 方法比較的Field,都應該用來計算hashCode 值。

5.4.2、重寫equals() 方法的基本原則

以自定義的Customer類為例,何時需要重寫equals()?

  • 當一個類有自己特有的“邏輯相等”概念,當改寫equals()的時候,總是要改寫hashCode(),根據一個類的equals方法(改寫后),兩個截然不同的實例有可能在邏輯上是相等的,但是,根據Object.hashCode()方法,它們僅僅是兩個對象。
  • 因此,違反了“相等的對象必須具有相等的散列碼”。
  • 結論:復寫equals方法的時候一般都需要同時復寫hashCode方法。通常參與計算hashCode的對象的屬性也應該參與到equals()中進行計算。

5.4.3、Eclipse/IDEA工具里hashCode()的重寫

以Eclipse/IDEA為例,在自定義類中可以調用工具自動重寫equals和hashCode。問題:為什么用Eclipse/IDEA復寫hashCode方法,有31這個數字?

  • 選擇系數的時候要選擇盡量大的系數。因為如果計算出來的hash地址越大,所謂的“沖突”就越少,查找起來效率也會提高。(減少沖突)
  • 并且31只占用5bits,相乘造成數據溢出的概率較小。
  • 31可以由i*31== (i<<5)-1來表示,現在很多虛擬機里面都有做相關優化。(提高算法效率)
  • 31是一個素數,素數作用就是如果我用一個數字來乘以這個素數,那么最終出來的結果只能被素數本身和被乘數還有1來整除!(減少沖突)
/*** 2.要求:向Set(主要指:HashSet、LinkedHashSet)中添加的數據,其所在的類一定要重寫hashCode()和equals()*   要求:重寫的hashCode()和equals()盡可能保持一致性:相等的對象必須具有相等的散列碼*        重寫兩個方法的小技巧:對象中用作 equals() 方法比較的 Field,都應該用來計算 hashCode 值。*/

5.5、LinkedHashSet的使用

  • LinkedHashSet是HashSet的子類
  • LinkedHashSet根據元素的hashCode值來決定元素的存儲位置,但它同時使用雙向鏈表維護元素的次序,這使得元素看起來是以插入順序保存的。
  • LinkedHashSet插入性能略低于HashSet,但在迭代訪問Set 里的全部元素時有很好的性能。
  • LinkedHashSet不允許集合元素重復。

在這里插入圖片描述

1、測試類

import org.junit.Test;import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;public class SetTest {/*** LinkedHashSet的使用* LinkedHashSet作為HashSet的子類,在添加數據的同時,每個數據還維護了兩個引用,記錄此數據前一個* 數據和后一個數據。* 優點:對于頻繁的遍歷操作,LinkedHashSet效率高于HashSet*/@Testpublic void test2(){Set set = new LinkedHashSet();set.add(456);set.add(123);set.add(123);set.add("AA");set.add("CC");set.add(new User("Tom",12));set.add(new User("Tom",12));set.add(129);Iterator iterator = set.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}}
}
public class User{private String name;private int age;public User() {}public User(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;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {System.out.println("User equals()....");if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;User user = (User) o;if (age != user.age) return false;return name != null ? name.equals(user.name) : user.name == null;}@Overridepublic int hashCode() { //return name.hashCode() + age;int result = name != null ? name.hashCode() : 0;result = 31 * result + age;return result;}
}

5.6、TreeSet的自然排序

  • TreeSet是SortedSet接口的實現類,TreeSet可以確保集合元素處于排序狀態。
  • TreeSet底層使用紅黑樹結構存儲數據
  • 新增的方法如下:(了解)
    • Comparator comparator()
    • Object first()
    • Object last()
    • Object lower(Object e)
    • Object higher(Object e)
    • SortedSet subSet(fromElement, toElement)
    • SortedSet headSet(toElement)
    • SortedSet tailSet(fromElement)
  • TreeSet兩種排序方法:自然排序和定制排序。默認情況下,TreeSet采用自然排序。
  • TreeSet和后面要講的TreeMap采用紅黑樹的存儲結構
  • 特點:有序,查詢速度比List快
  • 自然排序:TreeSet會調用集合元素的compareTo(Object obj) 方法來比較元素之間的大小關系,然后將集合元素按升序(默認情況)排列。
  • 如果試圖把一個對象添加到TreeSet時,則該對象的類必須實現Comparable 接口。
    • 實現Comparable 的類必須實現compareTo(Object obj) 方法,兩個對象即通過compareTo(Object obj) 方法的返回值來比較大小。
  • Comparable 的典型實現:
    • BigDecimal、BigInteger 以及所有的數值型對應的包裝類:按它們對應的數值大小進行比較
    • Character:按字符的unicode值來進行比較
    • Boolean:true 對應的包裝類實例大于false 對應的包裝類實例
    • String:按字符串中字符的unicode 值進行比較
    • Date、Time:后邊的時間、日期比前面的時間、日期大
  • 向TreeSet中添加元素時,只有第一個元素無須比較compareTo()方法,后面添加的所有元素都會調用compareTo()方法進行比較。
  • 因為只有相同類的兩個實例才會比較大小,所以向TreeSet中添加的應該是同一個類的對象。
  • 對于TreeSet集合而言,它判斷兩個對象是否相等的唯一標準是:兩個對象通過compareTo(Object obj) 方法比較返回值。
  • 當需要把一個對象放入TreeSet中,重寫該對象對應的equals() 方法時,應保證該方法與compareTo(Object obj) 方法有一致的結果:如果兩個對象通過equals() 方法比較返回true,則通過compareTo(Object obj) 方法比較應返回0。否則,讓人難以理解。

紅黑樹

在這里插入圖片描述

1、測試類

import org.junit.Test;import java.util.Iterator;
import java.util.TreeSet;/*** 1.向TreeSet中添加的數據,要求是相同類的對象。* 2.兩種排序方式:自然排序(實現Comparable接口) 和 定制排序(Comparator)* 3.自然排序中,比較兩個對象是否相同的標準為:compareTo()返回0.不再是equals().* 4.定制排序中,比較兩個對象是否相同的標準為:compare()返回0.不再是equals().*/
public class TreeSetTest {@Testpublic void test() {TreeSet set = new TreeSet();//失敗:不能添加不同類的對象
//        set.add(123);
//        set.add(456);
//        set.add("AA");
//        set.add(new User("Tom",12));//舉例一:
//        set.add(34);
//        set.add(-34);
//        set.add(43);
//        set.add(11);
//        set.add(8);//舉例二:set.add(new User("Tom",12));set.add(new User("Jerry",32));set.add(new User("Jim",2));set.add(new User("Mike",65));set.add(new User("Jack",33));set.add(new User("Jack",56));Iterator iterator = set.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}}
}

2、User類

public class User implements Comparable{private String name;private int age;public User() {}public User(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;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {System.out.println("User equals()....");if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;User user = (User) o;if (age != user.age) return false;return name != null ? name.equals(user.name) : user.name == null;}@Overridepublic int hashCode() { //return name.hashCode() + age;int result = name != null ? name.hashCode() : 0;result = 31 * result + age;return result;}//按照姓名從大到小排列,年齡從小到大排列@Overridepublic int compareTo(Object o) {if (o instanceof User) {User user = (User) o;
//            return this.name.compareTo(user.name);  //按照姓名從小到大排列
//            return -this.name.compareTo(user.name);  //按照姓名從大到小排列int compare = -this.name.compareTo(user.name);  //按照姓名從大到小排列if(compare != 0){   //年齡從小到大排列return compare;}else{return Integer.compare(this.age,user.age);}} else {throw new RuntimeException("輸入的類型不匹配");}}
}

5.7、TreeSet的定制排序

  • TreeSet的自然排序要求元素所屬的類實現Comparable接口,如果元素所屬的類沒有實現Comparable接口,或不希望按照升序(默認情況)的方式排列元素或希望按照其它屬性大小進行排序,則考慮使用定制排序。定制排序,通過Comparator接口來實現。需要重寫compare(T o1,T o2)方法。
  • 利用int compare(T o1,T o2)方法,比較o1和o2的大小:如果方法返回正整數,則表示o1大于o2;如果返回0,表示相等;返回負整數,表示o1小于o2。
  • 要實現定制排序,需要將實現Comparator接口的實例作為形參傳遞給TreeSet的構造器。
  • 此時,仍然只能向TreeSet中添加類型相同的對象。否則發生ClassCastException異常。
  • 使用定制排序判斷兩個元素相等的標準是:通過Comparator比較兩個元素返回了0。

1、測試類

import org.junit.Test;import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;/*** 1.向TreeSet中添加的數據,要求是相同類的對象。* 2.兩種排序方式:自然排序(實現Comparable接口) 和 定制排序(Comparator)* 3.自然排序中,比較兩個對象是否相同的標準為:compareTo()返回0.不再是equals().* 4.定制排序中,比較兩個對象是否相同的標準為:compare()返回0.不再是equals().*/
public class TreeSetTest {@Testpublic void tets2(){Comparator com = new Comparator() {//按照年齡從小到大排列@Overridepublic 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());}else{throw new RuntimeException("輸入的數據類型不匹配");}}};TreeSet set = new TreeSet(com);set.add(new User("Tom",12));set.add(new User("Jerry",32));set.add(new User("Jim",2));set.add(new User("Mike",65));set.add(new User("Mary",33));set.add(new User("Jack",33));set.add(new User("Jack",56));Iterator iterator = set.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}}
}

2、User類

public class User implements Comparable{private String name;private int age;public User() {}public User(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;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {System.out.println("User equals()....");if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;User user = (User) o;if (age != user.age) return false;return name != null ? name.equals(user.name) : user.name == null;}@Overridepublic int hashCode() { //return name.hashCode() + age;int result = name != null ? name.hashCode() : 0;result = 31 * result + age;return result;}//按照姓名從大到小排列,年齡從小到大排列@Overridepublic int compareTo(Object o) {if (o instanceof User) {User user = (User) o;
//            return this.name.compareTo(user.name);  //按照姓名從小到大排列
//            return -this.name.compareTo(user.name);  //按照姓名從大到小排列int compare = -this.name.compareTo(user.name);  //按照姓名從大到小排列if(compare != 0){   //年齡從小到大排列return compare;}else{return Integer.compare(this.age,user.age);}} else {throw new RuntimeException("輸入的類型不匹配");}}
}

2、User類

public class User implements Comparable{private String name;private int age;public User() {}public User(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;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {System.out.println("User equals()....");if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;User user = (User) o;if (age != user.age) return false;return name != null ? name.equals(user.name) : user.name == null;}@Overridepublic int hashCode() { //return name.hashCode() + age;int result = name != null ? name.hashCode() : 0;result = 31 * result + age;return result;}//按照姓名從大到小排列,年齡從小到大排列@Overridepublic int compareTo(Object o) {if (o instanceof User) {User user = (User) o;
//            return this.name.compareTo(user.name);  //按照姓名從小到大排列
//            return -this.name.compareTo(user.name);  //按照姓名從大到小排列int compare = -this.name.compareTo(user.name);  //按照姓名從大到小排列if(compare != 0){   //年齡從小到大排列return compare;}else{return Integer.compare(this.age,user.age);}} else {throw new RuntimeException("輸入的類型不匹配");}}
}

5.8、TreeSet的課后練習

在這里插入圖片描述

1、MyDate類

/*** MyDate類包含:* private成員變量year,month,day;并為每一個屬性定義getter,  setter 方法;*/
public class MyDate implements Comparable{private int year;private int month;private int day;public int getYear() {return year;}public void setYear(int year) {this.year = year;}public int getMonth() {return month;}public void setMonth(int month) {this.month = month;}public int getDay() {return day;}public void setDay(int day) {this.day = day;}public MyDate() {}public MyDate(int year, int month, int day) {this.year = year;this.month = month;this.day = day;}@Overridepublic String toString() {return "MyDate{" +"year=" + year +", month=" + month +", day=" + day +'}';}@Overridepublic int compareTo(Object o) {if(o instanceof MyDate){MyDate m = (MyDate)o;//比較年int minusYear = this.getYear() - m.getYear();if(minusYear != 0){return minusYear;}//比較月int minusMonth = this.getMonth() - m.getMonth();if(minusMonth != 0){return minusMonth;}//比較日return this.getDay() - m.getDay();}throw new RuntimeException("傳入的數據類型不一致!");}
}

2、Employee類

/*** 定義一個Employee類。* 該類包含:private成員變量name,age,birthday,* 其中birthday 為MyDate 類的對象;* 并為每一個屬性定義getter, setter 方法;* 并重寫toString 方法輸出name, age, birthday*/
public class Employee implements Comparable{private String name;private int age;private MyDate birthday;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;}public MyDate getBirthday() {return birthday;}public void setBirthday(MyDate birthday) {this.birthday = birthday;}public Employee() {}public Employee(String name, int age, MyDate birthday) {this.name = name;this.age = age;this.birthday = birthday;}@Overridepublic String toString() {return "Employee{" +"name='" + name + '\'' +", age=" + age +", birthday=" + birthday +'}';}//按name排序@Overridepublic int compareTo(Object o){if(o instanceof Employee){Employee e = (Employee)o;return this.name.compareTo(e.name);}
//        return 0;throw new RuntimeException("傳入的數據類型不一致");}
}

3、測試類

import org.junit.Test;import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;/*** 創建該類的5 個對象,并把這些對象放入TreeSet 集合中* (下一章:TreeSet 需使用泛型來定義)分別按以下兩種方式* 對集合中的元素進行排序,并遍歷輸出:** 1). 使Employee 實現Comparable 接口,并按name 排序* 2). 創建TreeSet 時傳入Comparator對象,按生日日期的先后排序。*/
public class EmployeeTest {//問題二:按生日日期的先后排序@Testpublic void test2(){TreeSet set = new TreeSet(new Comparator() {@Overridepublic int compare(Object o1, Object o2) {if(o1 instanceof Employee && o2 instanceof Employee){Employee e1 = (Employee)o1;Employee e2 = (Employee)o2;MyDate b1 = e1.getBirthday();MyDate b2 = e2.getBirthday();//方式一:
//                    //比較年
//                    int minusYear = b1.getYear() - b2.getYear();
//                    if(minusYear != 0){
//                        return minusYear;
//                    }
//
//                    //比較月
//                    int minusMonth = b1.getMonth() - b2.getMonth();
//                    if(minusMonth != 0){
//                        return minusMonth;
//                    }
//
//                    //比較日
//                    return b1.getDay() - b2.getDay();//方式二:return b1.compareTo(b2);}
//                return 0;throw new RuntimeException("傳入的數據類型不一致!");}});Employee e1 = new Employee("wangxianzhi",41,new MyDate(334,5,4));Employee e2 = new Employee("simaqian",43,new MyDate(-145,7,12));Employee e3 = new Employee("yanzhenqin",44,new MyDate(709,5,9));Employee e4 = new Employee("zhangqian",51,new MyDate(-179,8,12));Employee e5 = new Employee("quyuan",21,new MyDate(-340,12,4));set.add(e1);set.add(e2);set.add(e3);set.add(e4);set.add(e5);Iterator iterator = set.iterator();while (iterator.hasNext()){System.out.println(iterator.next());}}//問題一:使用自然排序@Testpublic void test(){TreeSet set = new TreeSet();Employee e1 = new Employee("wangxianzhi",41,new MyDate(334,5,4));Employee e2 = new Employee("simaqian",43,new MyDate(-145,7,12));Employee e3 = new Employee("yanzhenqin",44,new MyDate(709,5,9));Employee e4 = new Employee("zhangqian",51,new MyDate(-179,8,12));Employee e5 = new Employee("quyuan",21,new MyDate(-340,12,4));set.add(e1);set.add(e2);set.add(e3);set.add(e4);set.add(e5);Iterator iterator = set.iterator();while (iterator.hasNext()){System.out.println(iterator.next());}}
}

5.9、Set課后兩道面試題

練習:在List內去除重復數字值,要求盡量簡單

import org.junit.Test;import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;public class CollectionTest {//練習:在List內去除重復數字值,要求盡量簡單public static List duplicateList(List list) {HashSet set = new HashSet();set.addAll(list);return new ArrayList(set);}@Testpublic void test2(){List list = new ArrayList();list.add(new Integer(1));list.add(new Integer(2));list.add(new Integer(2));list.add(new Integer(4));list.add(new Integer(4));List list2 = duplicateList(list);for (Object integer : list2) {System.out.println(integer);}}
}

2、面試題

import org.junit.Test;import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;public class CollectionTest {@Testpublic void test3(){HashSet set = new HashSet();Person p1 = new Person(1001,"AA");Person p2 = new Person(1002,"BB");set.add(p1);set.add(p2);System.out.println(set);p1.name = "CC";set.remove(p1);System.out.println(set);set.add(new Person(1001,"CC"));System.out.println(set);set.add(new Person(1001,"AA"));System.out.println(set);}
}

06、Map接口

在這里插入圖片描述

6.1、Map接口及其多個實現類的對比

import org.junit.Test;import java.util.HashMap;
import java.util.Map;/*** 一、Map的實現類的結構:*  |----Map:雙列數據,存儲key-value對的數據   ---類似于高中的函數:y = f(x)*         |----HashMap:作為Map的主要實現類;線程不安全的,效率高;存儲null的key和value*              |----LinkedHashMap:保證在遍歷map元素時,可以按照添加的順序實現遍歷。*                      原因:在原有的HashMap底層結構基礎上,添加了一對指針,指向前一個和后一個元素。*                      對于頻繁的遍歷操作,此類執行效率高于HashMap。*         |----TreeMap:保證按照添加的key-value對進行排序,實現排序遍歷。此時考慮key的自然排序或定制排序*                      底層使用紅黑樹*         |----Hashtable:作為古老的實現類;線程安全的,效率低;不能存儲null的key和value*              |----Properties:常用來處理配置文件。key和value都是String類型***      HashMap的底層:數組+鏈表  (jdk7及之前)*                    數組+鏈表+紅黑樹 (jdk 8)**  面試題:*  1. HashMap的底層實現原理?*  2. HashMap 和 Hashtable的異同?*  3. CurrentHashMap 與 Hashtable的異同?(暫時不講)**/
public class MapTest {@Testpublic void test(){Map map = new HashMap();
//        map = new Hashtable();map.put(null,123);}
}

6.2、Map中存儲的key-value的特點

  • Map與Collection并列存在。用于保存具有映射關系的數據:key-value
  • Map 中的key 和value 都可以是任何引用類型的數據
  • Map 中的key 用Set來存放,不允許重復,即同一個Map 對象所對應的類,須重寫hashCode()和equals()方法
  • 常用String類作為Map的“鍵”
  • key 和value 之間存在單向一對一關系,即通過指定的key 總能找到唯一的、確定的value
  • Map接口的常用實現類:HashMap、TreeMap、LinkedHashMap和Properties。其中,HashMap是Map 接口使用頻率最高的實現類

在這里插入圖片描述

 /***  二、Map結構的理解:*    Map中的key:無序的、不可重復的,使用Set存儲所有的key  ---> key所在的類要重寫equals()和hashCode() (以HashMap為例)*    Map中的value:無序的、可重復的,使用Collection存儲所有的value --->value所在的類要重寫equals()*    一個鍵值對:key-value構成了一個Entry對象。*    Map中的entry:無序的、不可重復的,使用Set存儲所有的entry**/   

6.3、Map實現類之一:HashMap

  • HashMap是Map 接口使用頻率最高的實現類。
  • 允許使用null鍵和null值,與HashSet一樣,不保證映射的順序。
  • 所有的key構成的集合是Set:無序的、不可重復的。所以,key所在的類要重寫:equals()和hashCode()
  • 所有的value構成的集合是Collection:無序的、可以重復的。所以,value所在的類要重寫:equals()
  • 一個key-value構成一個entry
  • 所有的entry構成的集合是Set:無序的、不可重復的
  • HashMap 判斷兩個key 相等的標準是:兩個key 通過equals() 方法返回true,hashCode值也相等。
  • HashMap判斷兩個value相等的標準是:兩個value 通過equals() 方法返回true。

6.4、HashMap的底層實現原理

JDK 7及以前版本:HashMap是數組+鏈表結構(即為鏈地址法)
JDK 8版本發布以后:HashMap是數組+鏈表+紅黑樹實現。

在這里插入圖片描述

HashMap源碼中的重要常量

/**      DEFAULT_INITIAL_CAPACITY : HashMap的默認容量,16*      DEFAULT_LOAD_FACTOR:HashMap的默認加載因子:0.75*      threshold:擴容的臨界值,=容量*填充因子:16 * 0.75 => 12*      TREEIFY_THRESHOLD:Bucket中鏈表長度大于該默認值,轉化為紅黑樹:8*      MIN_TREEIFY_CAPACITY:桶中的Node被樹化時最小的hash表容量:64
*/

6.4.1、HashMap在JDK7中的底層實現原理

  • HashMap的內部存儲結構其實是數組和鏈表的結合。當實例化一個HashMap時,系統會創建一個長度為Capacity的Entry數組,這個長度在哈希表中被稱為容量(Capacity),在這個數組中可以存放元素的位置我們稱之為“桶”(bucket),每個bucket都有自己的索引,系統可以根據索引快速的查找bucket中的元素。
  • 每個bucket中存儲一個元素,即一個Entry對象,但每一個Entry對象可以帶一個引用變量,用于指向下一個元素,因此,在一個桶中,就有可能生成一個Entry鏈。而且新添加的元素作為鏈表的head。
  • 添加元素的過程:
    • 向HashMap中添加entry1(key,value),需要首先計算entry1中key的哈希值(根據key所在類的hashCode()計算得到),此哈希值經過處理以后,得到在底層Entry[]數組中要存儲的位置i。
    • 如果位置i上沒有元素,則entry1直接添加成功。
    • 如果位置i上已經存在entry2(或還有鏈表存在的entry3,entry4),則需要通過循環的方法,依次比較entry1中key的hash值和其他的entry的hash值。
    • 如果彼此hash值不同,則直接添加成功。
    • 如果hash值相同,繼續比較二者是否equals。如果返回值為true,則使用entry1的value去替換equals為true的entry的value。
    • 如果遍歷一遍以后,發現所有的equals返回都為false,則entry1仍可添加成功。entry1指向原有的entry元素。
/** 三、HashMap的底層實現原理?以jdk7為例說明:*    HashMap map = new HashMap():*    在實例化以后,底層創建了長度是16的一維數組Entry[] table。*    ...可能已經執行過多次put...*    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和原來的數據以鏈表的方式存儲。**   在不斷的添加過程中,會涉及到擴容問題,當超出臨界值(且要存放的位置非空)時,擴容。默認的擴容方式:擴容為原來容量的2倍,并將原有的數據復制過來。**//*** HashMap的擴容*     當HashMap中的元素越來越多的時候,hash沖突的幾率也就越來越高,*     因為數組的長度是固定的。所以為了提高查詢的效率,*     就要對HashMap的數組進行擴容,而在HashMap數組擴容之后,*     最消耗性能的點就出現了:原數組中的數據必須重新計算其在新數組中的位置,*     并放進去,這就是resize。*     * 那么HashMap什么時候進行擴容呢?*      當HashMap中的元素個數超過數組大小(數組總大小length,*      不是數組中個數size)*loadFactor時,就 會 進 行 數 組 擴 容,*      loadFactor的默認值(DEFAULT_LOAD_FACTOR)為0.75,這是一個折中的取值。*      也就是說,默認情況下,數組大小(DEFAULT_INITIAL_CAPACITY)為16,*      那么當HashMap中元素個數超過16*0.75=12(這個值就是代碼中的threshold值,*      也叫做臨界值)的時候,就把數組的大小擴展為2*16=32,即擴大一倍,*      然后重新計算每個元素在數組中的位置,而這是一個非常消耗性能的操作,*      所以如果我們已經預知HashMap中元素的個數,*      那么預設元素的個數能夠有效的提高HashMap的性能。*/

6.4.2、HashMap在JDK8中的底層實現原理

  • HashMap的內部存儲結構其實是數組+鏈表+紅黑樹的結合。當實例化一個HashMap時,會初始化initialCapacity和loadFactor,在put第一對映射關系時,系統會創建一個長度為initialCapacity的Node數組,這個長度在哈希表中被稱為容量(Capacity),在這個數組中可以存放元素的位置我們稱之為“桶”(bucket),每個bucket都有自己的索引,系統可以根據索引快速的查找bucket中的元素
  • 每個bucket中存儲一個元素,即一個Node對象,但每一個Node對象可以帶一個引用變量next,用于指向下一個元素,因此,在一個桶中,就有可能生成一個Node鏈。也可能是一個一個TreeNode對象,每一個TreeNode對象可以有兩個葉子結點left和right,因此,在一個桶中,就有可能生成一個TreeNode樹。而新添加的元素作為鏈表的last,或樹的葉子結點。
  • 那么HashMap什么時候進行擴容和樹形化呢?
    • 當HashMap中的元素個數超過數組大小(數組總大小length,不是數組中個數size)loadFactor時,就會進行數組擴容,loadFactor的默認值(DEFAULT_LOAD_FACTOR)為0.75,這是一個折中的取值。也就是說,默認情況下,數組大小(DEFAULT_INITIAL_CAPACITY)為16,那么當HashMap中元素個數超過160.75=12(這個值就是代碼中的threshold值,也叫做臨界值)的時候,就把數組的大小擴展為2*16=32,即擴大一倍,然后重新計算每個元素在數組中的位置,而這是一個非常消耗性能的操作,所以如果我們已經預知HashMap中元素的個數,那么預設元素的個數能夠有效的提高HashMap的性能。
    • 當HashMap中的其中一個鏈的對象個數如果達到了8個,此時如果capacity沒有達到64,那么HashMap會先擴容解決,如果已經達到了64,那么這個鏈會變成紅黑樹,結點類型由Node變成TreeNode類型。當然,如果當映射關系被移除后,下次resize方法時判斷樹的結點個數低于6個,也會把紅黑樹再轉為鏈表。
  • 關于映射關系的key是否可以修改?answer:不要修改
    映射關系存儲到HashMap中會存儲key的hash值,這樣就不用在每次查找時重新計算每一個Entry或Node(TreeNode)的hash值了,因此如果已經put到Map中的映射關系,再修改key的屬性,而這個屬性又參與hashcode值的計算,那么會導致匹配不上。
/* 總結:*   jdk8 相較于jdk7在底層實現方面的不同:*      1.new HashMap():底層沒有創建一個長度為16的數組*      2.jdk 8底層的數組是:Node[],而非Entry[]*      3.首次調用put()方法時,底層創建長度為16的數組*      4.jdk7底層結構只有:數組+鏈表。jdk8中底層結構:數組+鏈表+紅黑樹。*         4.1形成鏈表時,七上八下(jdk7:新的元素指向舊的元素。jdk8:舊的元素指向新的元素)*         4.2當數組的某一個索引位置上的元素以鏈表形式存在的數據個數 > 8 且當前數組的長度 > 64時,此時此索引位置上的所數據改為使用紅黑樹存儲。*/

6.7、LinkedHashMap的底層實現原理(了解)

  • LinkedHashMap是HashMap的子類
  • 在HashMap存儲結構的基礎上,使用了一對雙向鏈表來記錄添加元素的順序
  • 與LinkedHashSet類似,LinkedHashMap可以維護Map 的迭代順序:迭代順序與Key-Value 對的插入順序一致
  • HashMap中的內部類:Node
    在這里插入圖片描述
    在這里插入圖片描述
/**  四、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);*            }*        } */
import org.junit.Test;import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;public class MapTest {@Testpublic void test2(){Map map = new HashMap();map = new LinkedHashMap();map.put(123,"AA");map.put(345,"BB");map.put(12,"CC");System.out.println(map);}
}

6.8、Map中的常用方法1

import org.junit.Test;import java.util.*;
/***  五、Map中定義的方法:*      添加、刪除、修改操作:*      Object put(Object key,Object value):將指定key-value添加到(或修改)當前map對象中*      void putAll(Map m):將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是否為空*      boolean equals(Object obj):判斷當前map和參數對象obj是否相等*      元視圖操作的方法:*      Set keySet():返回所有key構成的Set集合*      Collection values():返回所有value構成的Collection集合*      Set entrySet():返回所有key-value對構成的Set集合**/
public class MapTest {/***  元素查詢的操作:*  Object get(Object key):獲取指定key對應的value*  boolean containsKey(Object key):是否包含指定的key*  boolean containsValue(Object value):是否包含指定的value*  int size():返回map中key-value對的個數*  boolean isEmpty():判斷當前map是否為空*  boolean equals(Object obj):判斷當前map和參數對象obj是否相等*/@Testpublic void test4(){Map map = new HashMap();map.put("AA",123);map.put(45,123);map.put("BB",56);// Object get(Object key)System.out.println(map.get(45));//containsKey(Object key)boolean isExist = map.containsKey("BB");System.out.println(isExist);isExist = map.containsValue(123);System.out.println(isExist);map.clear();System.out.println(map.isEmpty());}/*** 添加、刪除、修改操作:*  Object put(Object key,Object value):將指定key-value添加到(或修改)當前map對象中*  void putAll(Map m):將m中的所有key-value對存放到當前map中*  Object remove(Object key):移除指定key的key-value對,并返回value*  void clear():清空當前map中的所有數據*/@Testpublic void test3(){Map map = new HashMap();//添加map.put("AA",123);map.put(45,123);map.put("BB",56);//修改map.put("AA",87);System.out.println(map);Map map1 = new HashMap();map1.put("CC",123);map1.put("DD",456);map.putAll(map1);System.out.println(map);//remove(Object key)Object value = map.remove("CC");System.out.println(value);System.out.println(map);//clear()map.clear();//與map = null操作不同System.out.println(map.size());System.out.println(map);}
}

6.9、Map中的常用方法2

import org.junit.Test;import java.util.*;
/***  五、Map中定義的方法:*      添加、刪除、修改操作:*      Object put(Object key,Object value):將指定key-value添加到(或修改)當前map對象中*      void putAll(Map m):將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是否為空*      boolean equals(Object obj):判斷當前map和參數對象obj是否相等*      元視圖操作的方法:*      Set keySet():返回所有key構成的Set集合*      Collection values():返回所有value構成的Collection集合*      Set entrySet():返回所有key-value對構成的Set集合** 總結:常用方法:*    添加:put(Object key,Object value)*    刪除:remove(Object key)*    修改:put(Object key,Object value)*    查詢:get(Object key)*    長度:size()*    遍歷:keySet() / values() / entrySet()**  面試題:*  1. HashMap的底層實現原理?*  2. HashMap 和 Hashtable的異同?*      1.HashMap與Hashtable都實現了Map接口。由于HashMap的非線程安全性,效率上可能高于Hashtable。Hashtable的方法是Synchronize的,而HashMap不是,在多個線程訪問Hashtable時,不需要自己為它的方法實現同步,而HashMap 就必須為之提供外同步。*      2.HashMap允許將null作為一個entry的key或者value,而Hashtable不允許。*      3.HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因為contains方法容易讓人引起誤解。*      4.Hashtable繼承自Dictionary類,而HashMap是Java1.2引進的Map interface的一個實現。*      5.Hashtable和HashMap采用的hash/rehash算法都大概一樣,所以性能不會有很大的差異。**  3. CurrentHashMap 與 Hashtable的異同?(暫時不講)**/
public class MapTest {/***  元視圖操作的方法:*  Set keySet():返回所有key構成的Set集合*  Collection values():返回所有value構成的Collection集合*  Set entrySet():返回所有key-value對構成的Set集合*/@Testpublic void test5(){Map map = new HashMap();map.put("AA",123);map.put(45,1234);map.put("BB",56);//遍歷所有的key集:keySet()Set set = map.keySet();Iterator iterator = set.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}System.out.println("*****************");//遍歷所有的values集:values()Collection values = map.values();for(Object obj : values){System.out.println(obj);}System.out.println("***************");//遍歷所有的key-values//方式一:Set entrySet = map.entrySet();Iterator iterator1 = entrySet.iterator();while (iterator1.hasNext()){Object obj = iterator1.next();//entrySet集合中的元素都是entryMap.Entry entry = (Map.Entry) obj;System.out.println(entry.getKey() + "---->" + entry.getValue());}System.out.println("/");//方式二:Set keySet = map.keySet();Iterator iterator2 = keySet.iterator();while(iterator2.hasNext()){Object key = iterator2.next();Object value = map.get(key);System.out.println(key + "=====" + value);}}
}

6.10、TreeMap兩種添加方式的使用

  • TreeMap存儲Key-Value 對時,需要根據key-value 對進行排序。TreeMap可以保證所有的Key-Value 對處于有序狀態。
  • TreeSet底層使用紅黑樹結構存儲數據
  • TreeMap的Key 的排序:
    • 自然排序:TreeMap的所有的Key 必須實現Comparable 接口,而且所有的Key 應該是同一個類的對象,否則將會拋出ClasssCastException
    • 定制排序:創建TreeMap時,傳入一個Comparator 對象,該對象負責對TreeMap中的所有key 進行排序。此時不需要Map 的Key 實現Comparable 接口
  • TreeMap判斷兩個key相等的標準:兩個key通過compareTo()方法或者compare()方法返回0。

1、User類

public class User implements Comparable{private String name;private int age;public User() {}public User(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;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {System.out.println("User equals()....");if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;User user = (User) o;if (age != user.age) return false;return name != null ? name.equals(user.name) : user.name == null;}@Overridepublic int hashCode() { //return name.hashCode() + age;int result = name != null ? name.hashCode() : 0;result = 31 * result + age;return result;}//按照姓名從大到小排列,年齡從小到大排列@Overridepublic int compareTo(Object o) {if(o instanceof User){User user = (User)o;
//            return -this.name.compareTo(user.name);int compare = -this.name.compareTo(user.name);if(compare != 0){return compare;}else{return Integer.compare(this.age,user.age);}}else{throw new RuntimeException("輸入的類型不匹配");}}
}

2、測試類

import org.junit.Test;import java.util.*;public class TreeMapTest {/*** 向TreeMap中添加key-value,要求key必須是由同一個類創建的對象* 因為要按照key進行排序:自然排序 、定制排序*///自然排序@Testpublic void test(){TreeMap map = new TreeMap();User u1 = new User("Tom",23);User u2 = new User("Jerry",32);User u3 = new User("Jack",20);User u4 = new User("Rose",18);map.put(u1,98);map.put(u2,89);map.put(u3,76);map.put(u4,100);Set entrySet = map.entrySet();Iterator iterator1 = entrySet.iterator();while (iterator1.hasNext()){Object obj = iterator1.next();Map.Entry entry = (Map.Entry) obj;System.out.println(entry.getKey() + "---->" + entry.getValue());}}//定制排序@Testpublic void test2(){TreeMap map = new TreeMap(new Comparator() {@Overridepublic 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());}throw new RuntimeException("輸入的類型不匹配!");}});User u1 = new User("Tom",23);User u2 = new User("Jerry",32);User u3 = new User("Jack",20);User u4 = new User("Rose",18);map.put(u1,98);map.put(u2,89);map.put(u3,76);map.put(u4,100);Set entrySet = map.entrySet();Iterator iterator1 = entrySet.iterator();while (iterator1.hasNext()){Object obj = iterator1.next();Map.Entry entry = (Map.Entry) obj;System.out.println(entry.getKey() + "---->" + entry.getValue());}}
}

6.12、Hashtable

  • Hashtable是個古老的Map 實現類,JDK1.0就提供了。不同于HashMap,Hashtable是線程安全的。
  • Hashtable實現原理和HashMap相同,功能相同。底層都使用哈希表結構,查詢速度快,很多情況下可以互用。
  • 與HashMap不同,Hashtable不允許使用null 作為key 和value
  • 與HashMap一樣,Hashtable也不能保證其中Key-Value 對的順序
  • Hashtable判斷兩個key相等、兩個value相等的標準,與HashMap一致。

6.13、Properties處理屬性文件

  • Properties 類是Hashtable的子類,該對象用于處理屬性文件
  • 由于屬性文件里的key、value 都是字符串類型,所以Properties 里的key 和value 都是字符串類型
  • 存取數據時,建議使用setProperty(String key,Stringvalue)方法和getProperty(String key)方法

1、新建jdbc.properties文件

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

2、編寫源代碼

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;public class PropertiesTest {//Properties:常用來處理配置文件。key和value都是String類型public static void main(String[] args){//快捷鍵:ALT+Shift+ZFileInputStream fis = null;try {Properties pros = new Properties();fis = new FileInputStream("jdbc.properties");pros.load(fis); //加載流對應文件String name = pros.getProperty("name");String password = pros.getProperty("password");System.out.println("name = " + name + ",password = " + password);} catch (IOException e) {e.printStackTrace();} finally {if(fis != null){try {fis.close();} catch (IOException e) {e.printStackTrace();}}}}
}

如果jdbc.properties文件中寫入為中文;
防止jdbc.properties出現中文亂碼,可根據如下解決:

在這里插入圖片描述
在這里插入圖片描述

07、Collections工具類

  • 操作數組的工具類:Arrays
  • Collections 是一個操作Set、List和Map 等集合的工具類
  • Collections 中提供了一系列靜態的方法對集合元素進行排序、查詢和修改等操作,還提供了對集合對象設置不可變、對集合對象實現同步控制等方法
  • 排序操作:(均為static方法)
    • reverse(List):反轉List 中元素的順序
    • shuffle(List):對List集合元素進行隨機排序
    • sort(List):根據元素的自然順序對指定List 集合元素按升序排序
    • sort(List,Comparator):根據指定的Comparator 產生的順序對List 集合元素進行排序
    • swap(List,int,int):將指定list 集合中的i處元素和j 處元素進行交換

7.1、Collections工具類常用方法的測試

import org.junit.Test;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;/*** Collections:操作Collection、Map的工具類** 面試題:Collection 和 Collections的區別?*       Collection是集合類的上級接口,繼承于他的接口主要有Set 和List.*       Collections是針對集合類的一個幫助類,他提供一系列靜態方法實現對各種集合的搜索、排序、線程安全化等操作.*/
public class CollectionTest {/*** reverse(List):反轉 List 中元素的順序* shuffle(List):對 List 集合元素進行隨機排序* sort(List):根據元素的自然順序對指定 List 集合元素按升序排序* sort(List,Comparator):根據指定的 Comparator 產生的順序對 List 集合元素進行排序* swap(List,int, int):將指定 list 集合中的 i 處元素和 j 處元素進行交換** Object max(Collection):根據元素的自然順序,返回給定集合中的最大元素* Object max(Collection,Comparator):根據 Comparator 指定的順序,返回給定集合中的最大元素* Object min(Collection)* Object min(Collection,Comparator)* int frequency(Collection,Object):返回指定集合中指定元素的出現次數* void copy(List dest,List src):將src中的內容復制到dest中* boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替換 List 對象的所有舊值**/@Testpublic void test(){List list = new ArrayList();list.add(123);list.add(43);list.add(765);list.add(765);list.add(765);list.add(-97);list.add(0);System.out.println(list);//        Collections.reverse(list);
//        Collections.shuffle(list);
//        Collections.sort(list);
//        Collections.swap(list,1,2);int frequency = Collections.frequency(list, 123);System.out.println(list);System.out.println(frequency);}@Testpublic void test2(){List list = new ArrayList();list.add(123);list.add(43);list.add(765);list.add(-97);list.add(0);//報異常:IndexOutOfBoundsException("Source does not fit in dest")
//        List dest = new ArrayList();
//        Collections.copy(dest,list);//正確的:List dest = Arrays.asList(new Object[list.size()]);System.out.println(dest.size());//list.size();Collections.copy(dest,list);System.out.println(dest);/*** Collections 類中提供了多個 synchronizedXxx() 方法,* 該方法可使將指定集合包裝成線程同步的集合,從而可以解決* 多線程并發訪問集合時的線程安全問題*///返回的list1即為線程安全的ListList list1 = Collections.synchronizedList(list);}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/696133.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/696133.shtml
英文地址,請注明出處:http://en.pswp.cn/news/696133.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在idea中配置Tomcat

1.在idea中點擊右上角 2.點擊Edit Configurations,點擊加號 3.向下拉找到Tomcat Server下的Local,點一下 點擊Configure 找到tomcat文件路徑,選擇apache-tomcat-8.5.63(8.5.63是我的版本號) 選擇好路徑后點ok就配置好了 總步驟:

Vue 圖片輪播第三方庫 Vue-awesome-swiper介紹及簡單例子

vue-awesome-swiper 是一個基于 Swiper 的 Vue 輪播圖組件&#xff0c;Swiper 是一個流行的移動端觸摸滑動插件。它為 Vue.js 應用提供了一套豐富的輪播組件&#xff0c;支持多種布局和功能&#xff0c;如自動播放、無限循環、觸摸滑動等。 安裝 首先&#xff…

代碼隨想錄算法訓練營第一天

● 今日學習的文章鏈接和視頻鏈接 ● 自己看到題目的第一想法 1. 704二分法&#xff1a; 方法一&#xff1a; 整個數組是 左閉右閉區間 [ ] left指針指向數組開始下標&#xff0c; right 指針指向數組最后下表nums.size()-1, mid為 (leftright) /2循環條件 left<rightnu…

打開stable diffusion webui時,提示缺少clip或clip安裝不上的解決方案(windows下的操作)

1.問題描述 打開stable diffusion webui時&#xff0c;提示缺少clip或clip安裝不上 2.解決方案 原因&#xff1a;stable diffusion webui環境中的clip其實是open_clip&#xff0c;不能用pip install clip安裝解決方法是直接到github下載 open_clip 代碼到本地&#xff0c;并…

linux環境ssh-rsa進行簽名\權限\登錄\原理(免密登錄)

linux環境ssh-rsa進行簽名權限登錄(免密登錄) SSH原理與運用什么是SSH?SSH的使用場景ssh-rsa獲取xshell環境登錄獲取ssh-rsa使用ssh-rsa登錄SHA系列SHA-1、SHA-256和RSA的區別RSA原理數論基礎RSA機制RSA數學密鑰生成公式RSA數學加密理論RSA數學簽名公式

小折疊也能成為主力機,全新小折疊旗艦華為Pocket 2正式發布

2024年2月22日&#xff0c;華為在三亞舉辦華為Pocket 2時尚盛典&#xff0c;正式發布其全新小折疊旗艦華為Pocket 2。一直以來&#xff0c;華為致力于萃取各界藝術靈感&#xff0c;不斷探尋科技美學的可能性&#xff0c;華為Pocket系列更是秉承將奢雅美學與尖端科技融為一體的理…

探索Redis是否為單線程的奧秘(文末送書)

&#x1f308;個人主頁&#xff1a;聆風吟 &#x1f525;系列專欄&#xff1a;數據結構、網絡奇遇記 &#x1f516;少年有夢不應止于心動&#xff0c;更要付諸行動。 文章目錄 &#x1f4cb;前言一. Redis中的多線程二. I/O多線程三. Redis中的多進程四. 結論五. 書籍推薦5.1 書…

高效時間管理法則

你是否天天在忙&#xff0c;是否忙的不得要領&#xff0c;認真領會時間管理的四象限工作法&#xff0c;它會讓你的工作變得高效。 目錄 一、時間管理的誤區 二、時間是如何被浪費的&#xff1f; 內部因素 外部因素 三、時間管理的5個階段 1.公雞型時間管理&#xff1a; …

第一個Qt程序中的秘密

創建第一個程序 首先我們打開Qt Creator 打開文件->New Projects... 菜單&#xff0c;創建我們的第一個Qt項目 選擇 Qt Widgets Application&#xff0c;點擊選擇...按鈕 之后&#xff0c;輸入項目名稱QtLearning&#xff0c;并選擇創建路徑&#xff0c; 在build system中選…

ConnectWise ScreenConnect 身份驗證繞過漏洞復現可RCE(CVE-2024-1709)

0x01 產品簡介 ConnectWise ScreenConnect ,是一款自托管的遠程桌面軟件應用,該款軟件允許用戶自行托管,可以在自己的服務器、個人電腦、虛擬機或虛擬專用服務器上運行。 0x02 漏洞概述 ConnectWise ScreenConnect低于23.9.8 版本的產品中,SetupWizard.aspx接口處存在身…

Android14 InputManager-焦點窗口的更新

設置焦點時需要 先設置焦點APP mFo-cusedApp是一個AppWindowToken&#xff0c;在WMS中用來表示當前處于Resume狀態的Activity。它是由AMS在開始啟動一個Activity時調用WMS的setFocusedApp&#xff08;&#xff09;函數設置的。 考慮以下應用場景&#xff0c;當用戶從Launche…

內存管理——線性內存,進程空間

低2G為進程空間 開始地址結束地址大小屬性00xFFFFF1M保留0x1000000x102FFF棧不固定位置、大小0x1030000x143FFF堆不固定位置、大小0x400000主程序文件不固定位置、大小加載dll不固定位置、大小0x7ffdd000TIB位置&#xff0c;大小編譯時固定0x7FFFE000系統與用戶共享數據塊位置…

[newstarctf2023] --RE wp

AndroGenshin: rc4加密表&#xff0c;base64換表&#xff1a; 腳本梭就行 python username b"genshinimpact" base64_table [125, 239, 101, 151, 77, 163, 163, 110, 58, 230, 186, 206, 84, 84, 189, 193, 30, 63, 104, 178, 130, 211,164, 94, 75, 16, 32, 33…

發布 rust 源碼包 (crates.io)

rust 編程語言的包 (或者 庫, library) 叫做 crate, 也就是軟件中的一個組件. 一個完整的軟件通常由多個 crate 組成, rust 編譯器 (rustc) 一次編譯一整個 crate, 不同的 crate 可以同時并行編譯. rust 官方有一個集中發布開源包的網站 crates.io. 發布在這上面的 crate 可以…

uniapp微信公眾號H5分享

如果項目文件node_modules中沒有weixin-js-sdk文件&#xff0c;則直接使用本文章提供的&#xff1b; 如果不生效&#xff0c;則在template.h5.html中引入 <script src"https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script> 首先引入weixin-js-…

vue3框架組件自動導入unplugin-vue-components

1.安裝 npm i unplugin-vue-components -save-dev 2.配置 我這里用的是Vue CLI&#xff0c;所以要在vue.config.js文件中添加配置&#xff0c;官網中有寫不同打包工具的配置寫法 框架我使用的是Element Plus&#xff0c;使用前去官網查看自己的框架是否支持&#xff0c;主流…

LLM之RAG實戰(二十七)| 如何評估RAG系統

有沒有想過今天的一些應用程序是如何看起來幾乎神奇地智能的&#xff1f;這種魔力很大一部分來自于一種叫做RAG和LLM的東西。把RAG&#xff08;Retrieval Augmented Generation&#xff09;想象成人工智能世界里聰明的書呆子&#xff0c;它會挖掘大量信息&#xff0c;準確地找到…

電腦黑屏什么都不顯示怎么辦 電腦開機黑屏不顯示任何東西的4種解決辦法

相信有很多網友都有經歷電腦開機黑屏不顯示任何東西&#xff0c;找了很多方法都沒處理好&#xff0c;其實關于這個的問題&#xff0c;首先還是要了解清楚開機黑屏的原因&#xff0c;才能夠對癥下藥&#xff0c;下面大家可以跟小編一起來看看怎么解決吧 電腦開機黑屏不顯示任何…

【無刷電機學習】基礎概念及原理介紹(持續更新中...)

目錄&#xff08;2024.02.22版&#xff09; 1 定義 2 各種電機優勢比較 2.1 有刷與無刷比較 2.2 交流與直流比較 2.3 內轉子與外轉子比較 2.4 低壓BLDC的一些優點 3 基本原理 3.1 單相無刷電機 3.2 三相無刷電機 4 驅動方法 4.1 六步換相控制 4.1.1 基本原理 4…

突發!AI獨角獸「竹間智能」被曝停工停產6個月

大家好我是二狗。 今天早上起來刷朋友圈&#xff0c;看到一張截圖——AI創企竹間智能&#xff0c;宣稱因為公司所處的經營環境艱難&#xff0c;部分部門和崗位將從即日起停工停產6個月。 圖源&#xff1a;&#xff08;企服科學&#xff09; 下面是文字版&#xff1a; 由于公司…