1. 程式人生 > 實用技巧 >常用API、正則表示式,泛型、Collection集合API

常用API、正則表示式,泛型、Collection集合API

主要內容

  • Date類
    • Java是面向物件的思想,會用一個類來代表一個事物。
    • Date代表了系統當前此刻日期物件!年月日時分秒。
  • DateFormat類
    • 日期格式化類,認為日期物件拿到的時間是不好看的!
    • 日期格式化類可以把時間格式化成我們喜歡的格式。
    • 日期格式化類可以把字串時間解析成日期物件!! "2019-10-01 09:28:00"
  • Calendar類
    • 日曆類,代表了此刻日期物件對應的日曆物件。日曆的資訊更加的豐富。
  • System類
    • 代表了當前JVM虛擬機器對應的作業系統物件。
    • 可以拿系統時間。
    • 可以讓程式退出JVM虛擬機器,讓程式立即死亡!!
    • 可以做陣列拷貝。
  • StringBuilder類
    • String類不適合做字串的拼接,增刪等運算。不可變字串,增刪效能較差!
    • StringBuillder非常適合做字串的增刪改查操作,效能更好!!
  • 包裝類
    • 一切皆物件。
    • int Integer int age = 21; Integer age1 = 21;
    • float Float
    • double Double
  • 泛型
    • ArrayLIst lists = new ArrayList<>();
  • Collection集合:List , Map , Set
    • 三天的集合框架(重點內容,開發必用的!!)

教學目標

  • 能夠使用日期類輸出當前日期

    • Date d = new Date();
    • System.out.println(d);
  • 能夠使用將日期格式化為字串的方法

    • SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    • String rs = sdf.format(“日期物件”)
    • String rs = sdf.format("時間毫秒值")
  • 能夠使用將字串轉換成日期的方法

    • SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    • String str = "2019-11-11 11:11:11";
    • Data d = sdf.parse(str );
    • System.out.println(d);
  • 能夠使用System類的陣列複製方法

    // 3.陣列拷貝:
    int[] arrs1 = {10 , 20 , 30 , 40 , 50 , 60 , 70 , 80};
    // arrs2 = [ 0 , 0 , 0 , 0 , 0 , 0]
    // arrs2 = [0 , 0 , 30 , 40 , 50 , 0]
    // 希望把第一個陣列的 30 , 40 , 50賦值到第二個陣列!
    int[] arrs2 = new int[6];
    
    /**
     arraycopy(Object src,  int  srcPos,
     Object dest, int destPos,
     int length)
     引數一:原陣列。
     引數二:從原陣列哪個位置開始複製
     引數三:目標陣列
     引數四:複製到目標陣列的哪個位置開始。
     引數五:複製多少個!
     */
    System.arraycopy(arrs1, 2 ,arrs2 , 2 , 3);
    System.out.println(Arrays.toString(arrs2));
    
  • 能夠使用System類獲取當前毫秒時刻值

    long time = System.currentTimeMillis();
    
  • 能夠說出使用StringBuilder類可以解決的問題

    • 可以做字串的運算(拼接,增刪,反轉)
  • 能夠使用StringBuilder進行字串拼接操作

    • append
  • 能夠說出8種基本型別對應的包裝類名稱

    • int Integer

    • char Character

      基本資料型別              包裝類
          byte                 Byte
          short                Short
          int                  Integer(特殊)
          long                 Long
          float                Float
          double               Double
          char                 Character(特殊)
          boolean              Boolean
    
  • 能夠說出自動裝箱、自動拆箱的概念

  自動裝箱:可以直接把基本資料型別的變數或者值賦值給對應的包裝類物件。
  自動拆箱:可以把包裝類的物件賦值給基本資料型別的變數。
  ```

- 能夠將字串轉換為對應的基本型別

```properties
功能3: 把字串型別的數字轉化成對應的基本資料型別的值!!(真的有用,而且挺重要)
          Xxxx.parseXxxx("字串型別的數字")
          Xxxx.valueOf("字串型別的數字"):推薦使用的!
  • 能夠將基本型別轉換為對應的字串

    // 功能2: 包裝類可以把基本資料型別的值轉換成字串。
    // 1.把基本資料型別的值轉換成字串:toString()
    Integer num = 23 ;
    String numStr1 = num.toString();
    System.out.println(numStr1+1); // 231
    
    // 2.把基本資料型別的值轉換成字串:
    Integer num1 = 23 ;
    String num1Str1 = Integer.toString(num1);
    System.out.println(num1Str1+1); // 231
    
    // 3.把基本資料型別的值轉換成字串:
    Integer num2 = 23 ;
    String num2Str1 = num2 + "" ; //常見做法!
    System.out.println(num2Str1+1); // 231
    
  • 能夠說出Collection集合的常用功能

    Collection集合作為集合的根類,它的功能是一切集合都可以直接使用的。
     - public boolean add(E e):  把給定的物件新增到當前集合中 。
     - public void clear() :清空集合中所有的元素。
     - public boolean remove(E e): 把給定的物件在當前集合中刪除。
     - public boolean contains(Object obj): 判斷當前集合中是否包含給定的物件。
     - public boolean isEmpty(): 判斷當前集合是否為空。
     - public int size(): 返回集合中元素的個數。
     - public Object[] toArray(): 把集合中的元素,儲存到陣列中
    
  • 能夠使用泛型建立集合物件

     ArrayList<String> lists = new ArrayList<>(); // JDK 1.7之後泛型的簡化寫法!
     ArrayList<Integer> lists1 = new ArrayList<>();// JDK 1.7之後泛型的簡化寫法!
    
  • 能夠理解泛型上下限

    • ? extends Car : ?必須是Car的子類或者本身 。 上限
    • ? super Car : ?必須是Car的父類或者本身 。 下限 不用的!!
  • 能夠闡述泛型萬用字元的作用

    • ? 可以在使用泛型的時候,代表接收一切型別

第一章 DateFormat類

java.text.DateFormat 是日期/時間格式化子類的抽象類,我們通過這個類可以幫我們完成日期和文字之間的轉換,也就是可以在Date物件與String物件之間進行來回轉換。

  • 格式化:按照指定的格式,把Date物件轉換為String物件。(格式化時間)
  • 解析:按照指定的格式,把String物件轉換為Date物件。(解析字串時間)

1.1 構造方法

由於DateFormat為抽象類,不能直接使用,所以需要常用的子類java.text.SimpleDateFormat。這個類需要一個模式(格式)來指定格式化或解析的標準。構造方法為:

  • public SimpleDateFormat(String pattern):用給定的模式和預設語言環境的日期格式符號構造SimpleDateFormat。引數pattern是一個字串,代表日期時間的自定義格式。

1.2 格式規則

常用的格式規則為:

標識字母(區分大小寫) 含義
y
M
d
H
m
s
EEE
a 上午/下午

備註:更詳細的格式規則,可以參考SimpleDateFormat類的API文件。

1.3 常用方法

DateFormat類的常用方法有:

  • public String format(Date date):將Date物件格式化為字串。

  • public String format(time):將時間戳time格式化為字串

  • public Date parse(String source):將字串解析為Date物件。

    public class SimpleDateFormatDemo {
        public static void main(String[] args) throws ParseException {
            //格式化:從 Date 到 String
            Date d = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
            String s = sdf.format(d);
            System.out.println(s);
            // 格式化:從時間戳 到 String
            System.out.println(sdf.format(d.getTime()));
            System.out.println("--------");
    
            //從 String 到 Date
            String ss = "2048-08-09 11:11:11";
            //ParseException
            SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date dd = sdf2.parse(ss);
            System.out.println(dd);
        }
    }
    

面試題:“2019-11-04 09:30:30”往後1天15小時30分29秒後的時間是多少
```java
// 面試題:“2019-11-04 09:30:30”往後1天15小時30分29秒後的時間是多少

    // 定義一個字串時間
    String date = "2019-11-04 09:30:30";

    // 將字串的時間解析成Date日期物件
    // 注意:引數必須與被解析的時間完全一致,否則報錯
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    Date newDate = sdf.parse(date);

    // 得到日期物件的時間戳 + 往後走1天15小時30分29秒
    // 29加上L轉換成long來計算更安全
    long time = newDate.getTime() + 29L*1000 + 30L*60*1000 + 39L*60*60*1000;
    // 把時間戳轉換成字串的時間形式
    System.out.println(sdf.format(time));
```

小結:DateFormat可以將Date物件和字串相互轉換。

第二章 Calendar類

2.1 概述

  • java.util.Calendar類表示一個“日曆類”,可以進行日期運算。它是一個抽象類,不能建立物件,我們可以使用它的子類:java.util.GregorianCalendar類。

  • 有兩種方式可以獲取GregorianCalendar物件:

    • 直接建立GregorianCalendar物件;

    • 通過Calendar的靜態方法getInstance()方法獲取GregorianCalendar物件【本次課使用】

      Calendar rightNow = Calendar.getInstance();

2.2 常用方法

方法名 說明
public static Calendar getInstance() 獲取一個它的子類GregorianCalendar物件。(單例類)
public int get(int field) 獲取某個欄位的值。field引數表示獲取哪個欄位的值,
可以使用Calender中定義的常量來表示:
Calendar.YEAR : 年
Calendar.MONTH :月
Calendar.DAY_OF_MONTH:月中的日期
Calendar.HOUR:小時
Calendar.MINUTE:分鐘
Calendar.SECOND:秒
Calendar.DAY_OF_WEEK:星期
public void set(int field,int value) 設定某個欄位的值
public void add(int field,int amount) 為某個欄位增加/減少指定的值

2.3 get方法示例

```java
public class Demo {
    public static void main(String[] args) {
        //1.獲取一個GregorianCalendar物件
        Calendar instance = Calendar.getInstance();//獲取子類物件

        //2.列印子類物件
        System.out.println(instance);

        //3.獲取屬性
        int year = instance.get(Calendar.YEAR);
        int month = instance.get(Calendar.MONTH) + 1;//Calendar的月份值是0-11
        int day = instance.get(Calendar.DAY_OF_MONTH);

        int hour = instance.get(Calendar.HOUR);
        int minute = instance.get(Calendar.MINUTE);
        int second = instance.get(Calendar.SECOND);

        int week = instance.get(Calendar.DAY_OF_WEEK);//返回值範圍:1--7,分別表示:"星期日","星期一","星期二",...,"星期六"

        System.out.println(year + "年" + month + "月" + day + "日" + 
                       	hour + ":" + minute + ":" + second);
        System.out.println(getWeek(week));

    }

    //查表法,查詢星期幾
    public static String getWeek(int w) {//w = 1 --- 7
        //做一個表(陣列)
        String[] weekArray = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
        //            索引      [0]      [1]       [2]      [3]       [4]      [5]      [6]
        //查表
        return weekArray[w - 1];
    }
}
```

2.4 set方法示例:

    public class Demo {
        public static void main(String[] args) {
            //設定屬性——set(int field,int value):
    		Calendar c1 = Calendar.getInstance();//獲取當前日期

    		//計算班長出生那天是星期幾(假如班長出生日期為:1998年3月18日)
    		c1.set(Calendar.YEAR, 1998);
    		c1.set(Calendar.MONTH, 3 - 1);//轉換為Calendar內部的月份值
    		c1.set(Calendar.DAY_OF_MONTH, 18);

    		int w = c1.get(Calendar.DAY_OF_WEEK);
    		System.out.println("班長出生那天是:" + getWeek(w));

            
        }
        //查表法,查詢星期幾
        public static String getWeek(int w) {//w = 1 --- 7
            //做一個表(陣列)
            String[] weekArray = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
            //            索引      [0]      [1]       [2]      [3]       [4]      [5]      [6]
            //查表
            return weekArray[w - 1];
        }
    }
    ```



## 2.5 add方法示例:

    ```java
    // 讓日曆往後走多少天
    public class Demo {
        public static void main(String[] args) {
            //計算200天以後是哪年哪月哪日,星期幾?
            Calendar c2 = Calendar.getInstance();//獲取當前日期
            c2.add(Calendar.DAY_OF_MONTH, 200);//日期加200

            int y = c2.get(Calendar.YEAR);
            int m = c2.get(Calendar.MONTH) + 1;//轉換為實際的月份
            int d = c2.get(Calendar.DAY_OF_MONTH);

            int wk = c2.get(Calendar.DAY_OF_WEEK);
            System.out.println("200天后是:" + y + "年" + m + "月" + d + "日" + getWeek(wk));

        }
        //查表法,查詢星期幾
        public static String getWeek(int w) {//w = 1 --- 7
            //做一個表(陣列)
            String[] weekArray = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
            //            索引      [0]      [1]       [2]      [3]       [4]      [5]      [6]
            //查表
            return weekArray[w - 1];
        }
    }
    ```



# 第三章 Math類

## 3.1 概述

- java.lang.Math(類): Math包含執行基本數字運算的方法。
- 它不能建立物件,它的構造方法被“私有”了。因為他內部都是“靜態方法”,通過“類名”直接呼叫即可。

## 3.2 常用方法

| 方法名                                       | 說明                |
| -------------------------------------------- | ------------------- |
| public static int abs(int a)                 | 獲取引數a的絕對值: |
| public static double ceil(double a)          | 向上取整            |
| public static double floor(double a)         | 向下取整            |
| public static double pow(double a, double b) | 獲取a的b次冪        |
| public static long round(double a)           | 四捨五入取整        |

## 3.3 示例程式碼

```java
    public class Demo {
        public static void main(String[] args) {
            System.out.println("-5的絕對值:" + Math.abs(-5));//5
            System.out.println("3.4向上取整:" + Math.ceil(3.4));//4.0
            System.out.println("3.4向下取整:" + Math.floor(3.4));//3.0
            System.out.println("2的8次冪:" + Math.pow(2, 8));//256.0
            System.out.println("3.2四捨五入:" + Math.round(3.2));//3
            System.out.println("3.5四捨五入:" + Math.round(3.5));//4

        }
    }
    ```



# 第四章 System

## 4.1 概述

`java.lang.System`類中提供了大量的靜態方法,可以獲取與系統相關的資訊或系統級操作。

## 4.2 常用方法

| 方法名                                   | 說明                                             |
| ---------------------------------------- | ------------------------------------------------ |
| public   static void exit(int status)    | 終止當前執行的   Java   虛擬機器,非零表示異常終止 |
| public   static long currentTimeMillis() | 返回當前時間(以毫秒為單位)                       |

## 4.3 練習

在控制檯輸出1-10000,計算這段程式碼執行了多少毫秒 

```java
    import java.util.Date;
    //驗證for迴圈列印數字1-9999所需要使用的時間(毫秒)
    public class SystemDemo {
        public static void main(String[] args) {
            //獲取當前時間毫秒值
           System.out.println(System.currentTimeMillis()); 
          //計算程式執行時間
           long start = System.currentTimeMillis();
            for (int i = 1; i <= 10000; i++) {
                System.out.println(i);
            }
            long end = System.currentTimeMillis();
            System.out.println("共耗時毫秒:" + (end - start));
        }  
    }
    ```

# 第五章 BigDecimal類

## 5.1 引入

浮點數做運算精度問題;

看程式說結果:

```java
    public static void main(String[] args) {
        System.out.println(0.09 + 0.01);
        System.out.println(1.0 - 0.32);
        System.out.println(1.015 * 100);
        System.out.println(1.301 / 100);
    }
    ```

## 5.2 概述

| 相關內容 | 具體描述                                                     |
| -------- | :----------------------------------------------------------- |
| 包       | java.math                                                                  使用時需要導包 |
| 類宣告   | public class BigDecimal extends Number implements Comparable<BigDecimal> |
| 描述     | BigDecimal類提供了算術,縮放操作,舍入,比較,雜湊和格式轉換的操作。提供了更加精準的資料計算方式 |

## 5.3 構造方法

| 構造方法名             | 描述                                            |
| ---------------------- | ----------------------------------------------- |
| BigDecimal(double val) | 將double型別的資料封裝為BigDecimal物件          |
| BigDecimal(String val) | 將 BigDecimal 的字串表示形式轉換為 BigDecimal |

注意:推薦使用第二種方式,第一種存在精度問題;

> 建立物件的方式(最好的方式):

    ```java
    // public static BigDecimal valueOf(double val); // 包裝浮點數成為大資料物件

    public class BigDecimalDemo {
        public static void main(String[] args) {
            double a = 0.1;
            double b = 0.2;
            // 把浮點數轉換成大資料物件
            BigDecimal a1 = BigDecimal.valueOf(a);
            BigDecimal b1 = BigDecimal.valueOf(b);
            BigDecimal c1 = a1.add(b1);
            // BigDecimal只是解決精度問題的手段,double資料才是我們的目的!
            double rs = c1.doubleValue();
            System.out.println(rs);
        }
    }
    ```



## 5.4 常用方法

BigDecimal類中使用最多的還是提供的進行四則運算的方法,如下:

| 方法宣告                                     | 描述                         |
| -------------------------------------------- | ---------------------------- |
| public BigDecimal add(BigDecimal value)      | 加法運算                     |
| public BigDecimal subtract(BigDecimal value) | 減法運算                     |
| public BigDecimal multiply(BigDecimal value) | 乘法運算                     |
| public BigDecimal divide(BigDecimal value)   | 除法運算                     |
| public double doubleValue()                  | 把BigDecimal轉換成double型別 |

注意:對於divide方法來說,如果除不盡的話,就會出現java.lang.ArithmeticException異常。此時可以使用divide方法的另一個過載方法;

> BigDecimal divide(BigDecimal divisor, int scale, int roundingMode): divisor:除數對應的BigDecimal物件;scale:精確的位數;roundingMode取捨模式

> 小結:Java中小數運算有可能會有精度問題,如果要解決這種精度問題,可以使用BigDecimal

# 第六章 正則表示式

## 6.1 正則表示式的概念及演示

- 在Java中,我們經常需要驗證一些字串,例如:年齡必須是2位的數字、使用者名稱必須是8位長度而且只能包含大小寫字母、數字等。正則表示式就是用來驗證各種字串的規則。它內部描述了一些規則,我們可以驗證使用者輸入的字串是否匹配這個規則。
- 先看一個不使用正則表示式驗證的例子:下面的程式讓使用者輸入一個QQ號碼,我們要驗證:
  - QQ號碼必須是5--15位長度
  - 而且必須全部是數字
  - 而且首位不能為0

    ```java
    public class Demo {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            
            System.out.println("請輸入你的QQ號碼:");
            String qq = sc.next();
            
            System.out.println(checkQQ(qq));
        }
        //我們自己編寫程式碼,驗證QQ號碼
        private static boolean checkQQ(String qq) {
            //1.驗證5--15位
            if(qq.length() < 5 || qq.length() > 15){
                return false;
            }
            //2.必須都是數字;
            for(int i = 0;i < qq.length() ; i++){
                char c = qq.charAt(i);
                if(c < '0' || c > '9'){
                    return false;
                }
            }
            //3.首位不能是0;
            char c = qq.charAt(0);
            if(c == '0'){
                return false;
            }
            return true;//驗證通過
        }
        
    }
    ```

- 使用正則表示式驗證:

    ```java
    public class Demo {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            
            System.out.println("請輸入你的QQ號碼:");
            String qq = sc.next();
            
            System.out.println(checkQQ2(qq));
        }
        //使用正則表示式驗證
        private static boolean checkQQ2(String qq){
            String regex = "[1-9]\\d{4,14}";//正則表示式
            return qq.matches(regex);
        }
    }
    ```

上面程式checkQQ2()方法中String型別的變數regex就儲存了一個"正則表示式 ",而這個正則表示式就描述了我們需要的三個規則。matches()方法是String類的一個方法,用於接收一個正則表示式,並將"本物件"與引數"正則表示式"進行匹配,如果本物件符合正則表示式的規則,則返回true,否則返回false。

**我們接下來就重點學習怎樣寫正則表示式**

## 6.2 正則表示式-字元類

- 語法示例:

1. \[abc\]:代表a或者b,或者c字元中的一個。
2. \[^abc\]:代表除a,b,c以外的任何字元。
3. [a-z]:代表a-z的所有小寫字元中的一個。
4. [A-Z]:代表A-Z的所有大寫字元中的一個。
5. [0-9]:代表0-9之間的某一個數字字元。
6. [a-zA-Z0-9]:代表a-z或者A-Z或者0-9之間的任意一個字元。
7. [a-dm-p]:a 到 d 或 m 到 p之間的任意一個字元。 

- 程式碼示例:

    ```java
    public class Demo {
        public static void main(String[] args) {
            String str = "ead";
            
            //1.驗證str是否以h開頭,以d結尾,中間是a,e,i,o,u中某個字元
            String regex = "h[aeiou]d";
            System.out.println("1." + str.matches(regex));
            
            //2.驗證str是否以h開頭,以d結尾,中間不是a,e,i,o,u中的某個字元
            regex = "h[^aeiou]d";
            System.out.println("2." +  str.matches(regex));
            
            //3.驗證str是否a-z的任何一個小寫字元開頭,後跟ad
            regex = "[a-z]ad";
            System.out.println("3." + str.matches(regex));
            
            //4.驗證str是否以a-d或者m-p之間某個字元開頭,後跟ad
            regex = "[[a-d][m-p]]ad";
            System.out.println("4." + str.matches(regex));
        }
    }

    ```

## 6.3 正則表示式-邏輯運算子

- 語法示例:
  1. &&:並且
  2. |    :或者
- 程式碼示例:

    ```java
    public class Demo {
        public static void main(String[] args) {
            String str = "had";
            
            //1.要求字串是小寫子音字元開頭,後跟ad
            String regex = "[a-z&&[^aeiou]]ad";
            System.out.println("1." + str.matches(regex));
            
            //2.要求字串是aeiou中的某個字元開頭,後跟ad
            regex = "[a|e|i|o|u]ad";//這種寫法相當於:regex = "[aeiou]ad";
            System.out.println("2." + str.matches(regex));
        }
    }

    ```



## 6.4 正則表示式-預定義字元

- 語法示例:
  1. "." : 匹配任何字元。
  2. "\d":任何數字[0-9]的簡寫;
  3. "\D":任何非數字\[^0-9\]的簡寫;
  4. "\s": 空白字元:[ \t\n\x0B\f\r] 的簡寫
  5. "\S": 非空白字元:\[^\s\] 的簡寫
  6. "\w":單詞字元:[a-zA-Z_0-9]的簡寫
  7. "\W":非單詞字元:\[^\w\]
- 程式碼示例:

    ```java
    public class Demo {
        public static void main(String[] args) {
            String str = "258";
            
            //1.驗證str是否3位數字
            String regex = "\\d\\d\\d";
            System.out.println("1." + str.matches(regex));
            
            //2.驗證手機號:1開頭,第二位:3/5/8,剩下9位都是0-9的數字
            str = "13513153355";//要驗證的字串
            regex = "1[358]\\d\\d\\d\\d\\d\\d\\d\\d\\d";//正則表示式
            System.out.println("2." + str.matches(regex));
            
            //3.驗證字串是否以h開頭,以d結尾,中間是任何字元
            str = "had";//要驗證的字串
            regex = "h.d";//正則表示式
            System.out.println("3." + str.matches(regex));
            
            //4.驗證str是否是:had.
            str = "had.";//要驗證的字串
            regex = "had\\.";//\\.代表'.'符號,因為.在正則中被預定義為"任意字元",不能直接使用
            System.out.println("4." + str.matches(regex));
            
        }
    }
    ```

## 6.5 正則表示式-數量詞

- 語法示例:
  1. X? : 0次或1次
  2. X* : 0次到多次
  3. X+ : 1次或多次
  4. X{n} : 恰好n次
  5. X{n,} : 至少n次
  6. X{n,m}: n到m次(n和m都是包含的)
- 程式碼示例:

    ```java
    public class Demo {
        public static void main(String[] args) {
            String str = "";
            
            //1.驗證str是否是三位數字
            str = "012";
            String regex = "\\d{3}";
            System.out.println("1." + str.matches(regex));
            
            //2.驗證str是否是多位數字
            str = "88932054782342";
            regex = "\\d+";
            System.out.println("2." + str.matches(regex));
            
            //3.驗證str是否是手機號:
            str = "13813183388";
            regex = "1[358]\\d{9}";
            System.out.println("3." + str.matches(regex));
            
            //4.驗證小數:必須出現小數點,但是隻能出現1次
            String s2 = "3.1";
            regex = "\\d*\\.{1}\\d+";
            System.out.println("4." + s2.matches(regex));
            
            //5.驗證小數:小數點可以不出現,也可以出現1次
            regex = "\\d+\\.?\\d+";
            System.out.println("5." + s2.matches(regex));
            
            //6.驗證小數:要求匹配:3、3.、3.14、+3.14、-3.
            s2 = "-3.";
            regex = "[+-]\\d+\\.?\\d*";
            System.out.println("6." + s2.matches(regex));
            
            //7.驗證qq號碼:1).5--15位;2).全部是數字;3).第一位不是0
            s2 = "1695827736";
            regex = "[1-9]\\d{4,14}";
            System.out.println("7." + s2.matches(regex));
        }
    }

    ```

## 6.6 正則表示式-分組括號( )

    ```java
    public class Demo {
        public static void main(String[] args) {
            String str = "DG8FV-B9TKY-FRT9J-99899-XPQ4G";
            
            //驗證這個序列號:分為5組,每組之間使用-隔開,每組由5位A-Z或者0-9的字元組成
            String regex = "([A-Z0-9]{5}-){4}[A-Z0-9]{5}";
            System.out.println(str.matches(regex));
        }
    }

    ```

## 6.7 String的split方法中使用正則表示式

- String類的split()方法原型:

    ```java
    public String[] split(String regex)//引數regex就是一個正則表示式。可以將當前字串中匹配regex正則表示式的符號作為"分隔符"來切割字串。
    ```

- 程式碼示例:

    ```java
    public class RegexDemo4 {
        public static void main(String[] args) {
            // 1、split基礎用法
            String names = "賈乃亮,王寶強,陳羽凡";
            // 以“,”分割
            String[] nameArrs = names.split(",");
    //        print(nameArrs);

            // 2、split結合正則表示式分割
            String names1 = "賈乃亮112312a3王寶強12312s35d35陳羽凡";
            String[] nameArrs1 = names1.split("\\w{1,}");
            print(nameArrs1);
        }

        public static void print(String[] str) {
            for (int i = 0; i < str.length; i++) {
                System.out.println(str[i]);
            }
        }
    }
    ```

## 6.8 String類的replaceAll方法中使用正則表示式

- String類的replaceAll()方法原型:

    ```java
    public String replaceAll(String regex,String newStr)//引數regex就是一個正則表示式。可以將當前字串中匹配regex正則表示式的字串替換為newStr。
    ```

- 程式碼示例:

    ```java
    public class Demo {
        public static void main(String[] args) {
            //將下面字串中的"數字"替換為"*"
            String str = "jfdk432jfdk2jk24354j47jk5l31324";
            System.out.println(str.replaceAll("\\d+", "*"));
        }
    }
    ```

## 6.9 正則表示式實際案例

```java
        // 校驗郵箱
        public static void checkEmail() {
            Scanner sc = new Scanner(System.in);
            System.out.print("請輸入您的郵箱:");
            String email = sc.nextLine();
            // [email protected]
            // [email protected]
            // [email protected]
            if (email.matches("\\w{1,}@\\w{2,10}(\\.\\w{2,10}){1,2}")) {
                System.out.println("郵箱驗證正確!");
            } else {
                System.err.println("郵箱格式不合法!");
            }
        }

        // 驗證手機號碼
        public static void checkPhone() {
            Scanner sc = new Scanner(System.in);
            System.out.print("請輸入您的手機號碼:");
            String phone = sc.nextLine();
            // 第一個數字時1,第二個數字時3-9
            if(phone.matches("1[3-9]\\d{9}")) {
                System.out.println("手機號碼驗證正確!");
            } else {
                System.err.println("手機號碼格式錯誤!");
            }
        }
    ```

    ```java
    /**
        在文章中爬取電話號碼和郵箱
    */
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;

    public class RegexDemo5 {
        public static void main(String[] args) {
            String rs = "歡迎致電南京郵電大學,電話020-43433424,或者聯絡郵箱" +
                        "[email protected],電話18762826338,0223232323" +
                        "郵箱[email protected],400-100-3233,4001003232";

            // 從上面爬取出電話號碼和郵箱
            // 1、定義爬取規則(郵箱 || 手機號 || 電話號碼1 || 電話號碼2)
            String regex = "(\\w{1,}@\\w{2,10}(\\.\\w{2,10}){1,2})|(1[3-9]\\d{9})|(0\\d{2,5}-?\\d{5,15})|(400-?\\d{3,8}-?\\d{3,8})";
            // 2、編譯表示式成為一個匹配規則物件
            Pattern pattern = Pattern.compile(regex);
            // 3、通過匹配規則物件得到一個匹配器物件
            Matcher matcher = pattern.matcher(rs);
            // 4、通過匹配器去內容中爬取資訊
            while(matcher.find()) {
                System.out.println(matcher.group());
            }
        }
    }
    ```



# 第七章  包裝類

## 7.1 概述

Java提供了兩個型別系統,基本型別與引用型別,使用基本型別在於效率,然而很多情況,會建立物件使用,因為物件可以做更多的功能,如果想要我們的基本型別像物件一樣操作,就可以使用基本型別對應的包裝類,如下:

| 基本型別 | 對應的包裝類(位於java.lang包中) |
| -------- | --------------------------------- |
| byte     | Byte                              |
| short    | Short                             |
| int      | **Integer**                       |
| long     | Long                              |
| float    | Float                             |
| double   | Double                            |
| char     | **Character**                     |
| boolean  | Boolean                           |

## 7.2 Integer類

- Integer類概述

  包裝一個物件中的原始型別 int 的值

- Integer類構造方法及靜態方法

| 方法名                                  | 說明                                   |
| --------------------------------------- | -------------------------------------- |
| public Integer(int   value)             | 根據 int 值建立 Integer 物件(過時)     |
| public Integer(String s)                | 根據 String 值建立 Integer 物件(過時)  |
| public static Integer valueOf(int i)    | 返回表示指定的 int 值的 Integer   例項 |
| public static Integer valueOf(String s) | 返回儲存指定String值的 Integer 物件    |

- 示例程式碼

    ```java
    public class IntegerDemo {
        public static void main(String[] args) {
            //public Integer(int value):根據 int 值建立 Integer 物件(過時)
            Integer i1 = new Integer(100);
            System.out.println(i1);

            //public Integer(String s):根據 String 值建立 Integer 物件(過時)
            Integer i2 = new Integer("100");
            //Integer i2 = new Integer("abc"); //NumberFormatException
            System.out.println(i2);
            System.out.println("--------");

            //public static Integer valueOf(int i):返回表示指定的 int 值的 Integer 例項
            Integer i3 = Integer.valueOf(100);
            System.out.println(i3);

            //public static Integer valueOf(String s):返回儲存指定String值的Integer物件 
            Integer i4 = Integer.valueOf("100");
            System.out.println(i4);
        }
    }
    ```

## 7.3 裝箱與拆箱

基本型別與對應的包裝類物件之間,來回轉換的過程稱為”裝箱“與”拆箱“:

- **裝箱**:從基本型別轉換為對應的包裝類物件。
- **拆箱**:從包裝類物件轉換為對應的基本型別。

用Integer與 int為例:(看懂程式碼即可)

基本數值---->包裝物件

    ```java
    Integer i = new Integer(4);//使用建構函式函式
    Integer iii = Integer.valueOf(4);//使用包裝類中的valueOf方法
    ```

包裝物件---->基本數值

    ```java
    int num = i.intValue();
    ```

## 7.4 自動裝箱與自動拆箱

由於我們經常要做基本型別與包裝類之間的轉換,從Java 5(JDK 1.5)開始,基本型別與包裝類的裝箱、拆箱動作可以自動完成。例如:

    ```java
    Integer i = 4; // 自動裝箱。相當於Integer i = Integer.valueOf(4);
    int c = i; // 自動拆箱
    i = i + 5;//等號右邊:將i物件轉成基本數值(自動拆箱) i.intValue() + 5;
    //加法運算完成後,再次裝箱,把基本數值轉成物件。
    ```

> 注意:常規開發Integer與int沒什麼區別,Integer容錯更高

## 7.5 基本型別與字串之間的轉換

### 基本型別轉換為String

- 轉換方式
- 方式一:直接在數字後加一個空字串
- 方式二:通過String類靜態方法valueOf()
- 示例程式碼

    ```java
    public class IntegerDemo {
        public static void main(String[] args) {
            //int --- String
            int number = 100;
            //方式1
            String s1 = number + "";
            System.out.println(s1);
            //方式2
            //public static String valueOf(int i)
            String s2 = String.valueOf(number);
            System.out.println(s2);
            System.out.println("--------");
        }
    }
    ```

### String轉換成基本型別 (重要)

除了Character類之外,其他所有包裝類都具有parseXxx靜態方法可以將字串引數轉換為對應的基本型別:

- `public static byte parseByte(String s)`:將字串引數轉換為對應的byte基本型別。
- `public static short parseShort(String s)`:將字串引數轉換為對應的short基本型別。
- **`public static int parseInt(String s)`:將字串引數轉換為對應的int基本型別。**
- **`public static long parseLong(String s)`:將字串引數轉換為對應的long基本型別。**
- `public static float parseFloat(String s)`:將字串引數轉換為對應的float基本型別。
- `public static double parseDouble(String s)`:將字串引數轉換為對應的double基本型別。
- `public static boolean parseBoolean(String s)`:將字串引數轉換為對應的boolean基本型別。

程式碼使用(僅以Integer類的靜態方法parseXxx為例)如:

- 轉換方式
  - 方式一:先將字串數字轉成Integer,再呼叫valueOf()方法
  - 方式二:通過Integer靜態方法parseInt()進行轉換
- 示例程式碼

    > ```java
    > // 只需要記住valueOf()方法,即可將String轉換成其他的資料型別(非常推薦)
    > String numStr = "23";
    > int numInt = Integer.valueOf(numStr);
    > 
    > String doubleStr = "99.9";
    > double doubleDb = Double.valueOf(doubleStr);
    > 
    > ```

    ```java
    public class IntegerDemo {
        public static void main(String[] args) {
            //String --- int
            String s = "100";
            //方式1:String --- Integer --- int
            Integer i = Integer.valueOf(s);
            //public int intValue()
            int x = i.intValue();
            System.out.println(x);
            //方式2
            //public static int parseInt(String s)
            int y = Integer.parseInt(s);
            System.out.println(y);
        }
    }
    ```

> 注意:如果字串引數的內容無法正確轉換為對應的基本型別,則會丟擲`java.lang.NumberFormatException`異常。





# 第八章 泛型(難點)

## 8.1  泛型概述

在前面學習集合時,我們都知道集合中是可以存放任意物件的,只要把物件儲存集合後,那麼這時他們都會被提升成Object型別。當我們在取出每一個物件,並且進行相應的操作,這時必須採用型別轉換。

大家觀察下面程式碼:

    ```java
    public class GenericDemo {
        public static void main(String[] args) {
            Collection coll = new ArrayList();
            coll.add("abc");
            coll.add("itcast");
            coll.add(5);//由於集合沒有做任何限定,任何型別都可以給其中存放
            Iterator it = coll.iterator();
            while(it.hasNext()){
                //需要列印每個字串的長度,就要把迭代出來的物件轉成String型別
                String str = (String) it.next();
                System.out.println(str.length());
            }
        }
    }
    ```

程式在執行時發生了問題**java.lang.ClassCastException**。                                                                                             為什麼會發生型別轉換異常呢?                                                                                                                                       我們來分析下:由於集合中什麼型別的元素都可以儲存。導致取出時強轉引發執行時 ClassCastException。                                                                                                                                                       怎麼來解決這個問題呢?                                                                                                                                                           Collection雖然可以儲存各種物件,但實際上通常Collection只儲存同一型別物件。例如都是儲存字串物件。因此在JDK5之後,新增了**泛型**(**Generic**)語法,讓你在設計API時可以指定類或方法支援泛型,這樣我們使用API的時候也變得更為簡潔,並得到了編譯時期的語法檢查。

* **泛型**:可以在類或方法中預支地使用未知的型別。

> tips:一般在建立物件時,將未知的型別確定具體的型別。當沒有指定泛型時,預設型別為Object型別。

## 8.2  使用泛型的好處

上一節只是講解了泛型的引入,那麼泛型帶來了哪些好處呢?

* 將執行時期的ClassCastException,轉移到了編譯時期變成了編譯失敗。
* 避免了型別強轉的麻煩。

通過我們如下程式碼體驗一下:

    ```java
    public class GenericDemo2 {
        public static void main(String[] args) {
            Collection<String> list = new ArrayList<String>();
            list.add("abc");
            list.add("itcast");
            // list.add(5);//當集合明確型別後,存放型別不一致就會編譯報錯
            // 集合已經明確具體存放的元素型別,那麼在使用迭代器的時候,迭代器也同樣會知道具體遍歷元素型別
            Iterator<String> it = list.iterator();
            while(it.hasNext()){
                String str = it.next();
                //當使用Iterator<String>控制元素型別後,就不需要強轉了。獲取到的元素直接就是String型別
                System.out.println(str.length());
            }
        }
    }
    ```

> tips:泛型是資料型別的一部分,我們將類名與泛型合併一起看做資料型別。

## 8.3  泛型的定義與使用

我們在集合中會大量使用到泛型,這裡來完整地學習泛型知識。

泛型,用來靈活地將資料型別應用到不同的類、方法、介面當中。將資料型別作為引數進行傳遞。

### 定義和使用含有泛型的類

> 泛型類的核心思想:把出現泛型變數的地方全部替換成傳輸的真實資料型別
>
> 類的範型變數用E表示

定義格式:

    ```
    修飾符 class 類名<代表泛型的變數> {  }
    ```

* 泛型變數建議使用`E`,`T`,`K`,`V`

    ```java
    public class GenericDemo {
        public static void main(String[] args) {
            MyArrayList<String> lists = new MyArrayList<>();
            lists.add("123"); // 泛型限制了方法只能新增String型別
            System.out.println(lists);
        }
    }

    //  需求:模擬ArrayList集合自定義一個集合MyArrayList集合
    class MyArrayList<E> {
        private static ArrayList lists = new ArrayList();

        public void add(E e) {
            lists.add(e);
        }

        public void remove(E e) {
            lists.remove(e);
        }

        @Override
        public String toString() {
            return lists.toString();
        }
    }
    ```



例如,API中的ArrayList集合:

泛型在定義的時候不具體,使用的時候才變得具體。在使用的時候確定泛型的具體資料型別。

    ```java
    class ArrayList<E>{ 
        public boolean add(E e){ }

        public E get(int index){ }
        ....
    }
    ```

使用泛型: 即什麼時候確定泛型。

**在建立物件的時候確定泛型**

 例如,`ArrayList<String> list = new ArrayList<String>();`

此時,變數E的值就是String型別,那麼我們的型別就可以理解為:

    ```java 
    class ArrayList<String>{ 
         public boolean add(String e){ }

         public String get(int index){  }
         ...
    }
    ```

再例如,`ArrayList<Integer> list = new ArrayList<Integer>();`

此時,變數E的值就是Integer型別,那麼我們的型別就可以理解為:

    ```java
    class ArrayList<Integer> { 
         public boolean add(Integer e) { }

         public Integer get(int index) {  }
         ...
    }
    ```

###  含有泛型的方法

> 方法範型變數用T表示

定義格式:

    ```
    修飾符 <代表泛型的變數> 返回值型別 方法名(引數){  }
    ```

例如,

    ```java
    public class MyGenericMethod {    
        public <MVP> void show(MVP mvp) {
            System.out.println(mvp.getClass());
        }
        
        public <MVP> MVP show2(MVP mvp) {   
            return mvp;
        }
    }
    ```

    **呼叫方法時,確定泛型的型別**

    ```java
    public class GenericMethodDemo {
        public static void main(String[] args) {
            // 建立物件
            MyGenericMethod mm = new MyGenericMethod();
            // 演示看方法提示
            mm.show("aaa");
            mm.show(123);
            mm.show(12.45);
        }
    }
    ```

### 含有泛型的介面

定義格式:

    ```
    修飾符 interface介面名<代表泛型的變數> {  }
    ```

例如,

    ```java
    public interface MyGenericInterface<E>{
	    public abstract void add(E e);
	
	    public abstract E getE();  
    }
    ```

使用格式:

**1、定義類時確定泛型的型別**

例如

    ```java
    public class MyImp1 implements MyGenericInterface<String> {
        @Override
        public void add(String e) {
            // 省略...
        }

        @Override
        public String getE() {
            return null;
        }
    }
    ```

此時,泛型E的值就是String型別。

 **2、始終不確定泛型的型別,直到建立物件時,確定泛型的型別**

 例如

    ```java
    public class MyImp2<E> implements MyGenericInterface<E> {
        @Override
        public void add(E e) {
             // 省略...
        }

        @Override
        public E getE() {
            return null;
        }
    }
    ```

確定泛型:

    ```java
    /*
     * 使用
     */
    public class GenericInterface {
        public static void main(String[] args) {
            MyImp2<String>  my = new MyImp2<String>();  
            my.add("aa");
        }
    }
    ```

## 8.4  泛型萬用字元

當使用泛型類或者介面時,傳遞的資料中,泛型型別不確定,可以通過萬用字元<?>表示。但是一旦使用泛型的萬用字元後,只能使用Object類中的共性方法,集合中元素自身方法無法使用。

> 在泛型中用`?`表示接收任意型別(在使用的時候使用,而不是定義的時候)

### 萬用字元基本使用

泛型的萬用字元:**不知道使用什麼型別來接收的時候,此時可以使用?,?表示未知萬用字元。**

此時只能接受資料,不能往該集合中儲存資料。

舉個例子大家理解使用即可:

```java
    public static void main(String[] args) {
        Collection<Intger> list1 = new ArrayList<Integer>();
        getElement(list1);
        Collection<String> list2 = new ArrayList<String>();
        getElement(list2);
    }
    public static void getElement(Collection<?> coll){}
    // ?代表可以接收任意型別
    泛型不存在繼承關係 Collection<Object> list = new ArrayList<String>();這種是錯誤的
    ```

### 萬用字元高階使用

之前設定泛型的時候,實際上是可以任意設定的,只要是類就可以設定。但是在JAVA的泛型中可以指定一個泛型的**上限**和**下限**。

**泛型的上限**:

* **格式**: `型別名稱 <? extends 類 > 物件名稱`
* **意義**: `只能接收該型別及其子類`

**泛型的下限**:

- **格式**: `型別名稱 <? super 類 > 物件名稱`
- **意義**: `只能接收該型別及其父型別`

比如:現已知Object類,String 類,Number類,Integer類,其中Number是Integer的父類

    ```java
    public static void main(String[] args) {
        Collection<Integer> list1 = new ArrayList<Integer>();
        Collection<String> list2 = new ArrayList<String>();
        Collection<Number> list3 = new ArrayList<Number>();
        Collection<Object> list4 = new ArrayList<Object>();
        
        getElement(list1);
        getElement(list2);//報錯
        getElement(list3);
        getElement(list4);//報錯
      
        getElement2(list1);//報錯
        getElement2(list2);//報錯
        getElement2(list3);
        getElement2(list4);
      
    }
    // 泛型的上限:此時的泛型?,必須是Number型別或者Number型別的子類
    public static void getElement1(Collection<? extends Number> coll){}
    // 泛型的下限:此時的泛型?,必須是Number型別或者Number型別的父類
    public static void getElement2(Collection<? super Number> coll){}
    ```


# 第九章 Collection集合

## 9.1 集合概述

在前面基礎班我們已經學習過並使用過集合ArrayList<E> ,那麼集合到底是什麼呢?

* **集合**:集合是java中提供的一種容器,可以用來儲存多個數據。

集合和陣列既然都是容器,它們有什麼區別呢?

* 陣列的長度是固定的。集合的長度是可變的。
* 陣列中儲存的是同一型別的元素,可以儲存任意型別資料。集合儲存的都是引用資料型別。如果想儲存基本型別資料需要儲存對應的包裝型別。

## 9.2  集合常用類的繼承體系

Collection:單列集合類的根介面,用於儲存一系列符合某種規則的元素,它有兩個重要的子介面,分別是`java.util.List`和`java.util.Set`。其中,`List`的特點是元素有序、元素可重複。`Set`的特點是元素不可重複。`List`介面的主要實現類有`java.util.ArrayList`和`java.util.LinkedList`,`Set`介面的主要實現類有`java.util.HashSet`和`java.util.LinkedHashSet`。

從上面的描述可以看出JDK中提供了豐富的集合類庫,為了便於初學者進行系統地學習,接下來通過一張圖來描述集合常用類的繼承體系

![](https://s1.ax1x.com/2020/09/27/0FElqJ.jpg)

注意:這張圖只是我們常用的集合有這些,不是說就只有這些集合。

集合本身是一個工具,它存放在java.util包中。在`Collection`介面定義著單列集合框架中最最共性的內容。

## 9.3 Collection 常用API

Collection是所有單列集合的父介面,因此在Collection中定義了單列集合(List和Set)通用的一些方法,這些方法可用於操作所有的單列集合。方法如下:

* `public boolean add(E e)`:  把給定的物件新增到當前集合中 。
* `public void clear()` :清空集合中所有的元素。
* `public boolean remove(E e)`: 把給定的物件在當前集合中刪除。
* `public boolean contains(Object obj)`: 判斷當前集合中是否包含給定的物件。
* `public boolean isEmpty()`: 判斷當前集合是否為空。
* `public int size()`: 返回集合中元素的個數。
* `public Object[] toArray()`: 把集合中的元素,儲存到陣列中

> tips: 有關Collection中的方法可不止上面這些,其他方法可以自行檢視API學習。

    ```java
    public class CollectionDemo {
        public static void main(String[] args) {
            Collection<String> sets = new HashSet<>();
            // 新增元素,成功返回true
            sets.add("vingkin");
            sets.add("趙和月");

            // 清空集合元素
    //        set.clear();

            // 判斷集合是否為空,為空true
            System.out.println(sets.isEmpty());

            // 獲取集合大小
            System.out.println(sets.size());

            // 判斷集合中是否包含某個元素
            System.out.println(sets.contains("vingkin"));

            // 刪除某個元素:預設刪除前面的第一個
            sets.remove("vingkin");

            // 把集合轉換成陣列
            Object[] arrs = sets.toArray();
            // Arrays.toString()方法是返回陣列內容
            System.out.println(Arrays.toString(arrs));

            // 直接將Hashset轉換成String型別陣列
            String[] arrs1 = sets.toArray(String[]::new); // 轉換成指定的陣列型別
            System.out.println(Arrays.toString(arrs1));
        }
    }
    ```

集合並集操作

`addAll()`方法