Java學習筆記(一):基礎概念和語法

foochane : https://foochane.cn/article/2019121501.html 

 1 基礎概念

 1.1 二進制

字節是計算機中最小存儲單元。計算機存儲任何的數據,都是以字節的形式存儲。8個bit(二進制位) 0000-0000表示爲1個字節,寫成1 byte或者1 B。html

- 8 bit = 1 Bjava

- 1024 B =1 KBgit

- 1024 KB =1 MBgithub

- 1024 MB =1 GB算法

- 1024 GB = 1 TB編程

 1.2 Java虛擬機

虛擬機是一種抽象化的計算機,經過在實際的計算機上仿真模擬各類計算機功能來實現的。Java虛擬機(Java Virtual Machine,JVM )有本身完善的硬體架構,如處理器、堆棧、寄存器等,還具備相應的指令系統。Java虛擬機屏蔽了與具體操做系統平臺相關的信息,使得Java程序只需生成在Java虛擬機上運行的目標代碼(字節碼),就能夠在多種平臺上不加修改地運行。數組

所謂的java虛擬機,就是一臺虛擬的機器。它是一款軟件,用來執行一系列虛擬計算機指令,大致上虛擬機能夠分爲系統虛擬機和程序虛擬機。Visual Box、VMWare就屬於系統虛擬機。他們徹底是對物理計算機的仿真,提供一個可運行完整操做系統的軟件平臺。而java虛擬機就是典型程序虛擬機,它專門爲執行單個計算機程序而設計,在java虛擬機中執行的指令咱們稱之爲java字節碼指令。java發展到今天,出現了不少虛擬機,最初sun使用的叫Classic的java虛擬機,到如今使用最普遍的是HotSpot虛擬機,除了sun之外還有BEA的JRockit,目前JRockit和HotSpot都被甲骨文公司收入旗下,大有整合的趨勢。安全

任何軟件的運行,都必需要運行在操做系統之上,而咱們用Java編寫的軟件能夠運行在任何的操做系架構

統上,這個特性稱爲Java語言的**跨平臺特性**。該特性是由JVM實現的,咱們編寫的程序運行在JVM上,而JVM運行在操做系統上。編程語言

 1.3 JRE  和 JDK

- JRE(Java Runtime Environment):是Java程序的運行時環境,包含 JVM 和運行時所須要的 核心類庫 。

-  JDK(Java Development Kit):是Java程序開發工具包,包含 JRE 和開發人員使用的工具。

咱們想要運行一個已有的Java程序,那麼只需安裝 JRE 便可。咱們想要開發一個全新的Java程序,那麼必須安裝 JDK 。

 1.4  常量和變量

- 常量:程序運行中固定不變的量

- 變量:程序中運行能夠變化的量

常量分類:

| 類型       | 含義                                   | 舉例                        |

| ---------- | -------------------------------------- | --------------------------- |

| 整數常量   | 全部的整數                             | 0,1, 567, -9             |

| 小數常量   | 全部的小數                             | 0.0, -0.1, 2.55           |

| 字符常量   | 單引號引發來,只能寫一個字符,必須有內容 | 'a' , ' ', '好'           |

| 字符串常量 | 雙引號引發來,能夠寫多個字符,也能夠不寫 | "A" ,"Hello" ,"你好" ,"" |

| 布爾常量   | 只有兩個值                             | true , false               |

| 空常量     | 只有一個值                             | null                        |

變量分類:

Java的數據類型分爲兩大類:

- 基本數據類型 :整數 、 浮點數 、 字符 、 布爾 。

- 引用數據類型 :類 、 數組 、 接口 。

| 數據類型     | 關鍵字         | 佔用內存 | 取值範圍              |

| ------------ | -------------- | -------- | --------------------- |

| 字節型       | byte           | 1個字節  | -128~127              |

| 短整型       | short          | 2個字節  | -32768~32767          |

| 整型         | int(默認)    | 4個字節  | $-2^{31}$~$2^{31}-1$  |

| 長整型       | long           | 8個字節  | $-2^{63}$~$2^{63}-1$  |

| 單精度浮點數 | float          | 4個字節  | 1.4013E-45~3.4028E+38 |

| 雙精度浮點數 | double(默認) | 8個字節  | 4.9E-324~1.7977E+308  |

| 字符型       | char           | 2個字節  | 0-65535               |

| 布爾類型     | boolean        | 1個字節  | true,false           |

>`long`類型:建議數據後加`L`表示

>`float`類型:建議數據後加`F`表示

 1.5 數據類型轉換

自動類型轉換(隱式)

- 特色:代碼不須要進行特殊處理,自動完成。

- 規則:數據範圍從小到大。

強制類型轉換(顯式)

- 特色:代碼須要進行特殊的格式處理,不能自動完成。

- 格式:範圍小的類型 範圍小的變量名 =(範圍小的類型) 本來範圍大的數據;

注意事項:

1. 強制類型轉換通常不推薦使用,由於有可能發生精度損失、數據溢出。

2.`byte/short/char`這三種類型均可以發生數學運算,例如加法「`+`」.

3.`byte/short/char`這三種類型在運算的時候,都會被首先**提高成爲int類型**,而後再計算。

4.`boolean`類型不能發生數據類型轉換

 1.6 運算符

 算數運算符

| 符號     | 說明                         |

| -------- | ---------------------------- |

| +        | 加法運算,字符串鏈接運算     |

| -        | 減法運算                     |

| *        | 乘法運算                     |

| /        | 除法運算                     |

| %        | 取模運算,兩個數字相除取餘數 |

| ++ 、 -- | 自增自減運算                 |

**前++和後++的區別**

```java

publicstaticvoidmain(String[] args) {

inta = 1;

intb = ++a;

System.out.println(a);//計算結果是2

System.out.println(b);//計算結果是2

}

```

```java

publicstaticvoidmain(String[] args) {

inta = 1;

intb = a++;

System.out.println(a);//計算結果是2

System.out.println(b);//計算結果是1

}

```

 賦值運算符

| 符號 | 說明   |

| ---- | ------ |

| =    | 等於號 |

| +=   | 加等於 |

| - =  | 減等於 |

| *=   | 乘等於 |

| /=   | 除等於 |

| %=   | 取模等 |

 比較運算符

| 符號 | 說明                                                         |

| ---- | ------------------------------------------------------------ |

| ==   | 比較符號兩邊數據是否相等,相等結果是true。                   |

| <    | 比較符號左邊的數據是否小於右邊的數據,若是小於結果是true。   |

| >    | 比較符號左邊的數據是否大於右邊的數據,若是大於結果是true。   |

| <=   | 比較符號左邊的數據是否小於或者等於右邊的數據,若是小於結果是true。 |

| >=   | 比較符號左邊的數據是否大於或者等於右邊的數據,若是小於結果是true。 |

| ! = | 不等於符號 ,若是符號兩邊的數據不相等,結果是true。          |

 邏輯運算符

| 符號       | 說明                                                         |

| ---------- | ------------------------------------------------------------ |

| && 短路與  | 1. 兩邊都是true,結果是true<br/>2. 一邊是false,結果是false<br/>**短路特色:符號左邊是false,右邊再也不運算** |

| \|\| 短路或 | 1. 兩邊都是false,結果是false<br/>2. 一邊是true,結果是true<br/>**短路特色: 符號左邊是true,右邊再也不運算** |

| ! 取反    | 1. ! true 結果是false<br/>2. ! false結果是true               |

  三元運算符

三元運算符格式:

```java

數據類型 變量名 = 布爾類型表達式?結果1:結果2;

```

示例:

```java

publicstaticvoidmain(String[] args) {

inti = (1==2?100:200);

System.out.println(i);//200

intj = (3<=4?500:600);

System.out.println(j);//500

}

```

 1.7  JShell腳本工具

JShell腳本工具是JDK9的新特性,當咱們編寫的代碼很是少的時候,而又不肯意編寫類,main方法,也不肯意去編譯和運行,這個時候可使用JShell工具。

啓動JShell工具,在DOS命令行直接輸入JShell命令。

 1.8 IDEA快捷鍵

| 快捷鍵                   | 功能                                   |

| ------------------------ | -------------------------------------- |

| Alt + Enter              | 導入包,自動代碼修正                   |

| Ctrl+Y                   | 刪除光標所在行                         |

| Ctrl+D                   | 複製光標所在行的內容,插入光標位置下面 |

| Ctrl+Alt+L               | 格式化代碼                             |

| Ctrl+/                   | 單行註釋                               |

| Ctrl+Shift+/             | 選中代碼註釋,多行註釋,再按取消註釋   |

| Alt+Ins                  | 自動生成代碼,toString,get,set等方法 |

| Alt+Shift+ 上下箭頭      | 移動當前代碼行                         |

| Shift+F6                 | 同時修改不一樣地方的同一個量             |

| 輸入sout                 | System.out.println();                  |

| 輸入psvm                 | public static void main(String[] args) |

| 輸入5.fori               | for(int i = 0; i < 5; i++)            |

| 輸入arr.fori或者arr.forr | for循環變量數組                        |

 2 流程控制語句

 2.1 判斷語句if-else

語句格式:

```java

if (判斷條件1) {

   執行語句1;  

} elseif (判斷條件2) {

   執行語句2;  

}

...

}elseif (判斷條件n) {

  執行語句n;   

} else {

   執行語句n+1;  

}

```

 2.2 選擇語句swich-case

語句格式:

```java

switch(表達式) {

case 常量值1:

    語句體1;

break;

case 常量值2:

    語句體2;

break;

  ...

default:

    語句體n+1;

break;

}

```

 2.3 循環語句

  循環語句for

語句格式:

```java

for(初始化表達式①; 布爾表達式②; 步進表達式④){

循環體③        

}

```

執行流程

執行順序:①②③④ >②③④>②③④…②不知足爲止。

①負責完成循環變量初始化

②負責判斷是否知足循環條件,不知足則跳出循環

③具體執行的語句

④循環後,循環條件所涉及變量的變化狀況

 循環語句while

語句格式1:

```java

初始化表達式①

while(布爾表達式②){

    循環體③

    步進表達式④

}

```

執行流程

執行順序:①②③④ >②③④>②③④…②不知足爲止。

①負責完成循環變量初始化。

②負責判斷是否知足循環條件,不知足則跳出循環。

③具體執行的語句。

④循環後,循環變量的變化狀況。

語句格式2:

```java

初始化表達式①

do{

    循環體③

    步進表達式④

}while(布爾表達式②);

```

執行流程

執行順序:①③④ >②③④>②③④…②不知足爲止。

①負責完成循環變量初始化。

②負責判斷是否知足循環條件,不知足則跳出循環。

③具體執行的語句

④循環後,循環變量的變化狀況

 2.4 break和continue

 break

使用場景:終止 switch或者循環

- 在選擇結構 switch語句中

- 在循環語句中

- 離開使用場景的存在是沒有意義的

示例:

```java

publicstaticvoidmain(String[] args) {

for (inti = 1; i<=10; i++) {

//需求:打印完兩次HelloWorld以後結束循環

if(i == 3){

break;

        }

System.out.println("HelloWorld"+i);

    }

}

```

 continue

使用場景:結束本次循環,繼續下一次的循環

示例:

```java

publicstaticvoidmain(String[] args) {

for (inti = 1; i <= 10; i++) {

//需求:不打印第三次HelloWorld

if(i == 3){

continue;

        }

System.out.println("HelloWorld"+i);

    }

}

```

 3 數組

 3.1 容器

容器: 是將多個數據存儲到一塊兒,每一個數據稱爲該容器的元素。

 3.2 數組概念

數組概念: 數組就是存儲數據長度固定的容器,保證多個數據的數據類型要一致。

 3.3 數組的定義

 方式一

格式:

```java

數組存儲的數據類型[] 數組名字 = new 數組存儲的數據類型[長度];

```

示例:

```java

int[] arr = newint[3];

```

 方式二

格式:

```java

數據類型[] 數組名 = new 數據類型[]{元素1,元素2,元素3...};

```

示例:

```java

int[] arr = newint[]{1,2,3,4,5};

```

 方式三

格式:

```java

數據類型[] 數組名 = {元素1,元素2,元素3...};

```

示例:

```java

int[] arr = {1,2,3,4,5};

```

【注意】:

1. 數組有定長特性,長度一旦指定,不可更改

2.`方式三`一樣也進行了`new`操做

 3.4 數組操做

- 索引: 每個存儲到數組的元素,都會自動的擁有一個編號,從0開始,這個自動編號稱爲數組索引(index),能夠經過數組的索引訪問到數組中的元素。

- 數組的長度: 每一個數組都具備長度,並且是固定的,Java中賦予了數組的一個屬性,能夠獲取到數組的長度,語句爲: `數組名 .length` ,屬性length的執行結果是數組的長度,int類型結果。由次能夠推斷出,數組的最大索引值爲` 數組名 .length-1 `。

- 索引訪問數組中的元素: `數組名[索引]`

示例:

``` java

publicstaticvoidmain(String[] args) {

//定義存儲int類型數組,賦值元素1,2,3,4,5

int[] arr = {1,2,3,4,5};

//爲0索引元素賦值爲6

    arr[0] = 6;

//獲取數組0索引上的元素

inti = arr[0];

System.out.println(i);

//直接輸出數組0索引元素

System.out.println(arr[0]);

}

```

 數組取最大值

代碼以下:

```java

publicstaticvoidmain(String[] args) {

int[] arr = { 5, 15, 2000, 10000, 100, 4000 };

//定義變量,保存數組中0索引的元素

intmax = arr[0];

//遍歷數組,取出每一個元素

for (inti = 0; i < arr.length; i++) {

//遍歷到的元素和變量max比較

//若是數組元素大於max

if (arr[i] > max) {

//max記錄住大值

        max = arr[i];

      }

    }

System.out.println("數組最大值是: " + max);

}

```

 數組反轉

代碼以下:

```java

publicstaticvoidmain(String[] args) {

int[] arr = { 1, 2, 3, 4, 5 };

/*

      循環中定義變量min=0最小索引

      max=arr.length‐1最大索引

      min++,max‐‐

      */

for (intmin = 0, max = arr.length ‐ 1; min <= max; min++, max‐‐) {

//利用第三方變量完成數組中的元素交換

inttemp = arr[min];

      arr[min] = arr[max];

      arr[max] = temp;

    }

// 反轉後,遍歷數組

for (inti = 0; i < arr.length; i++) {

System.out.println(arr[i]);

    }

}

```

 3.5 數組內存劃分

內存是計算機中的重要原件,臨時存儲區域,做用是運行程序。咱們編寫的程序是存放在硬盤中的,在硬盤中的程序是不會運行的,必須放進內存中才能運行,運行完畢後會清空內存。

Java虛擬機要運行程序,必需要對內存進行空間的分配和管理。

**Java的內存須要劃分紅爲5個部分:**

1. 棧(Stack): 存放的都是方法中的局部變量。**方法的運行必定要在棧當中運行。**

- 局部變量:方法的參數,或者是方法{}內部的變量

- 做用域:一旦超出做用域,馬上從棧內存當中消失。

2. 堆(Heap): 凡是new出來的東西,都在堆當中。

- 堆內存裏面的東西都有一一個地址值: 16進制

- 堆內存裏面的數據,都有默認值。規則:

- 若是是整數: 默認爲`0`

- 若是是浮點數:  默認爲`0.0`

- 若是是字符: 默認爲`'\u0000'`

- 若是是布爾:  默認爲`false`

- 若是是引用類型:  默認爲`null`

3. 方法區(Method Area): 存儲class相關信息,包含方法的信息。

4. 本地方法棧(Native Method Stack): 與操做系統相關。

5. 寄存器(PC Register): 與CPU相關。

示例:

```java

publicstaticvoidmain(String[] args) {

// 定義數組,存儲3個元素

int[] arr = newint[3];

//數組索引進行賦值

    arr[0] = 5;

    arr[1] = 6;

    arr[2] = 7;

//輸出3個索引上的元素值

System.out.println(arr[0]);

System.out.println(arr[1]);

System.out.println(arr[2]);

}

```

代碼執行流程:

1. main方法進入方法棧。程序運行前main方法存儲在方法區,程序運行時,main方法進入棧

2. 建立數組。JVM在堆內存中開闢一個內存空間存儲數組(new int[3]),數組中的三個元素默認值爲0。內存地址以一個十六進制數表示(0xff343)。

3. JVM將內存地址賦值給變量 arr。**變量arr保存的是數組內存中的地址,而不是一個具體的數值,所以數組爲引用數據類型。**

4. 根據數組索引給數組的3個元素賦值,分佈賦值爲5,6,7。而後進行打印。

![數組內存圖](https://foochane.cn/images/20...

兩個變量指向同一個數據:

```java

publicstaticvoidmain(String[] args) {

// 定義數組,存儲3個元素

int[] arr = newint[3];

//數組索引進行賦值

    arr[0] = 5;

    arr[1] = 6;

    arr[2] = 7;

//輸出3個索引上的元素值

System.out.println(arr[0]);

System.out.println(arr[1]);

System.out.println(arr[2]);

//定義數組變量arr2,將arr的地址賦值給arr2

int[] arr2 = arr;

    arr2[1] = 9;

System.out.println(arr[1]);

}

```

上述代碼中,arr和arr2都指向同一個內存地址,`arr2[1] = 9`執行後,`arr[1]`也會跟着改變。

 4   面向對象

Java語言是一種面向對象的程序設計語言,而面向對象思想是一種程序設計思想,咱們在面向對象思想的指引下,

使用Java語言去設計、開發計算機程序。 這裏的對象泛指現實中一切事物,每種事物都具有本身的屬性和行爲。面向對象思想就是在計算機程序設計過程當中,參照現實中事物,將事物的屬性特徵、行爲特徵抽象出來,描述成計算機事件的設計思想。 它區別於面向過程思想,強調的是經過調用對象的行爲來實現功能,而不是本身一步一步的去操做實現。 

面向對象思想是一種更符合咱們思考習慣的思想,它能夠將複雜的事情簡單化,並將咱們從執行者變成了指揮者。**面向對象的語言中,包含了三大基本特徵,即封裝、繼承和多態。**

 4.1 類和對象

-  類 :是一組相關**屬性**和**行爲**的集合。能夠當作是一類事物的模板,使用事物的屬性特徵和行爲特徵來描述該

  類事物。

- 屬性:事物的狀態信息。 

- 行爲:事物可以作什麼。

-  對象 :是一類事物的具體體現。對象是類的一個實例,必然具有該類事物的屬性和行爲。

-  類與對象的關係

- 類是對一類事物的描述,是**抽象的**。

- 對象是一類事物的實例,是**具體的**。

- 類是對象的模板,對象是類的實體 。

 4.2 類的定義

定義格式:

```java

publicclassClassName {

//成員變量

//成員方法

}

```

示例:

```java

publicclassStudent {

//成員變量  

String name;//姓名  

int age;//年齡

//成員方法

//學習的方法

publicvoidstudy() {

System.out.println("好好學習,每天向上");

  }

//吃飯的方法

  publicvoid eat() {

System.out.println("學習餓了要吃飯");

  }

}    

```

 4.3 對象使用

對象的使用格式

建立對象:

```java

類名 對象名 = new 類名();

```

使用對象訪問類中的成員:

```java

對象名.成員變量;

對象名.成員方法();

```

示例:

```java

publicclassTest01_Student {

publicstaticvoidmain(String[] args) {

//建立對象格式:類名 對象名 = new 類名();

Students = newStudent();

System.out.println("s:"+s); //cn.itcast.Student@100363

//直接輸出成員變量值

System.out.println("姓名:"+s.name); //null

System.out.println("年齡:"+s.age); //0

System.out.println("‐‐‐‐‐‐‐‐‐‐");

//給成員變量賦值

s.name = "趙麗穎";

s.age = 18;

//再次輸出成員變量的值

System.out.println("姓名:"+s.name); //趙麗穎

System.out.println("年齡:"+s.age); //18

System.out.println("‐‐‐‐‐‐‐‐‐‐");

//調用成員方法

s.study(); // "好好學習,每天向上"

s.eat(); // "學習餓了要吃飯"

  }

}

```

成員變量的默認值

- 基本類型:

- 整數(byte,short,int,long):`0`

- 浮點數(float,double):`0.0`

- 字符(char): `'\u0000'`

- 布爾(boolean):`false`

- 引用類型:數組,類,接口 `null`

 4.4 成員變量和局部變量區別

```java

publicclassCar{

Stringcolor; //成員變量

publicvoiddrive(){

intspeed = 80; //局部變量

//......

    }

}

```

- 在類中的位置不一樣

- 成員變量:類中,方法外

-  局部變量:方法中或者方法聲明上(形式參數)

- 做用範圍不同

- 成員變量:類中

- 局部變量:方法中

- 初始化值的不一樣

- 成員變量:有默認值

- 局部變量:沒有默認值。必須先定義,賦值,最後使用在內

- 存中的位置不一樣 

- 成員變量:堆內存

- 局部變量:棧內存

- 生命週期不一樣

- 成員變量:隨着對象的建立而存在,隨着對象的消失而消失

- 局部變量:隨着方法的調用而存在,隨着方法的調用完畢而消失           

 5 封裝

面向對象編程語言是對客觀世界的模擬,客觀世界裏成員變量都是隱藏在對象內部的,外界沒法直接操做和修改。封裝能夠被認爲是一個保護屏障,防止該類的代碼和數據被其餘類隨意訪問。要訪問該類的數據,必須經過指定的方式。適當的封裝可讓代碼更容易理解與維護,也增強了代碼的安全性。

封裝的步驟

1. 使用  private 關鍵字來修飾成員變量。

2. 對須要訪問的成員變量,提供對應的一對  getXxx 方法 、 setXxx 方法。

 5.1 private關鍵字

private的含義

1.`private`是一個權限修飾符,表明最小權限。

2. 能夠修飾成員變量和成員方法。

3. 被`private`修飾後的成員變量和成員方法,只在本類中才能訪問。

private的使用格式:

```java

private 數據類型 變量名;

```

1. 使用  private 修飾成員變量,代碼以下:

```java

publicclassStudent {

privateStringname;

privateintage;

}

```

2. 提供  getXxx 方法 /  setXxx 方法,能夠訪問成員變量,代碼以下:

```java

publicclassStudent {

privateStringname;

privateintage;

publicvoidsetName(Stringn) {

    name = n;

  }

publicStringgetName() {

return name;

  }

publicvoidsetAge(inta) {

    age = a;

  }

publicintgetAge() {

return age;

  }

}

```

 5.2 this關鍵字

this的含義this表明所在類的當前對象的引用(地址值),即對象本身的引用。

**方法被哪一個對象調用,方法中的`this`就表明那個對象。即誰在調用,this就表明誰。**

this使用格式:

```java

this.成員變量名;

```

使用  this 修飾方法中的變量,解決成員變量被隱藏的問題,代碼以下:

> 因爲形參變量名與成員變量名重名,致使成員變量名被隱藏,方法中的變量名,沒法訪問到成員變量,從而賦值失敗。因此,咱們只能使用this關鍵字,來解決這個重名問題。

```java

publicclassStudent {

privateStringname;

privateintage;

publicvoidsetName(Stringname) {

//name = name;

this.name = name;

  }

publicStringgetName() {

return name;

  }

publicvoidsetAge(intage) {

//age = age;

this.age = age;

  }

publicintgetAge() {

return age;

  }

```

 5.3 構造方法

當一個對象被建立時候,構造方法用來初始化該對象,給對象的成員變量賦初始值。

**不管你與否自定義構造方法,全部的類都有構造方法,由於Java自動提供了一個無參數構造方法,一旦本身定義了構造方法,Java自動提供的默認無參數構造方法就會失效。**

構造方法的定義格式:

```java

修飾符 構造方法名(參數列表){

// 方法體    

}

```

構造方法的寫法上,方法名與它所在的類名相同。它沒有返回值,因此不須要返回值類型,甚至不須要void。使用構造方法後,代碼以下:

```java

publicclassStudent {

privateStringname;

privateintage;

// 無參數構造方法

publicStudent() {}

// 有參數構造方法

publicStudent(Stringname,intage) {

this.name = name;

this.age = age;

  }

}

```

注意事項

1. 若是你不提供構造方法,系統會給出無參數構造方法。

2. 若是你提供了構造方法,系統將再也不提供無參數構造方法。

3. 構造方法是能夠重載的,既能夠定義參數,也能夠不定義參數。

 5.4 JavaBean

JavaBean 是 Java語言編寫類的一種標準規範。符合 JavaBean 的類,要求類必須是具體的和公共的,而且具備無參數的構造方法,提供用來操做成員變量的 set 和 get 方法。  

```java

publicclassClassName{

//成員變量

//構造方法

//無參構造方法【必須】

//有參構造方法【建議】

//成員方法   

//getXxx()

//setXxx()

}

```

編寫符合 JavaBean 規範的類,以學生類爲例,標準代碼以下:

```java

publicclassStudent {

//成員變量

privateStringname;

privateintage;

//構造方法

publicStudent() {}

publicStudent(Stringname,intage) {

this.name = name;

this.age = age;

  }

//成員方法

publicvoidsetName(Stringname) {

this.name = name;

  }

publicStringgetName() {

return name;

  }

publicvoidsetAge(intage) {

this.age = age;

  }

publicintgetAge() {

return age;

  }

}

```

 6 繼承

多個類中存在相同屬性和行爲時,將這些內容抽取到單獨一個類中,那麼多個類無需再定義這些屬性和行爲,只要繼承那一個類便可。

其中,多個類能夠稱爲子類,單獨那一個類稱爲父類、超類(superclass)或者基類。

父類更通用,子類更具體。咱們經過繼承,可使多種事物之間造成一種關係體系。

 6.1 定義

**繼承** :就是子類繼承父類的屬性和行爲,使得子類對象具備與父類相同的屬性、相同的行爲。子類能夠直接訪問父類中的非私有的屬性和行爲。

好處:

1. 提升代碼的複用性。

2. 類與類之間產生了關係,是多態的前提。

格式:

經過  `extends` 關鍵字,能夠聲明一個子類繼承另一個父類,定義格式以下:

```java

class父類 {

...    

}

class子類extends 父類 {

...    

}

```

示例:

```java

/*

 * 定義員工類Employee,作爲父類

 */

classEmployee {

Stringname; // 定義name屬性    

// 定義員工的工做方法    

publicvoidwork() {    

System.out.println("全力以赴地工做");        

    }    

}

/*

 * 定義講師類Teacher 繼承 員工類Employee

 */

classTeacherextendsEmployee {

// 定義一個打印name的方法    

publicvoidprintName() {    

System.out.println("name=" + name);        

    }    

}

/*

 * 定義測試類

 */

publicclassExtendDemo01 {

publicstaticvoidmain(String[] args) {    

// 建立一個講師類對象

Teachert = newTeacher();        

// 爲該員工類的name屬性進行賦值

t.name = "小明";         

// 調用該員工的printName()方法  

t.printName(); // name = 小明        

// 調用Teacher類繼承來的work()方法  

t.work();  // 全力以赴地工做  

    }    

}

```

  6.2 繼承後的特色

 成員變量

- 成員變量不重名

- 若是子類父類中出現不重名的成員變量,這時的訪問是沒有影響的。

- 成員變量重名

- 若是子類父類中出現重名的成員變量,這時的訪問是有影響的。

- 子父類中出現了同名的成員變量時,在子類中須要訪問父類中非私有成員變量時,須要使用 `super` 關鍵字,修飾父類成員變量,相似於以前學過的 ` this` 。

 成員方法

- 成員方法不重名

- 若是子類父類中出現不重名的成員方法,這時的調用是沒有影響的。

- 對象調用方法時,會先在子類中查找有沒有對應的方法,若子類中存在就會執行子類中的方法,若子類中不存在就會執行父類中相應的方法。

- 成員方法重名 ——**重寫(Override)**

- 若是子類父類中出現重名的成員方法,這時的訪問是一種特殊狀況,叫作方法重寫(Override)。

 構造方法

- 構造方法的名字是與類名一致的。因此子類是沒法繼承父類構造方法的。

- 構造方法的做用是初始化成員變量的。因此子類的初始化過程當中,必須先執行父類的初始化動做。子類的構造方法中默認有一個 super() ,表示調用父類的構造方法,父類成員變量初始化後,才能夠給子類使用。

```java

classFu {

privateintn;

Fu(){

System.out.println("Fu()");

  }

}

classZiextendsFu {

Zi(){

// super(),調用父類構造方法

super();

System.out.println("Zi()");

  } 

}

publicclassExtendsDemo07{

publicstaticvoidmain (Stringargs[]){

Zizi = newZi();

  }

}

輸出結果:

Fu()

Zi()

```

 Java繼承特色

Java只支持單繼承,不支持多繼承。

 6.3 重寫(Override)

方法重寫 :子類中出現與父類如出一轍的方法時(返回值類型,方法名和參數列表都相同),會出現覆蓋效果,也稱爲重寫或者複寫。聲明不變,從新實現。

示例:

子類能夠根據須要,定義特定於本身的行爲。既沿襲了父類的功能名稱,又根據子類的須要從新實現父類方法,從而進行擴展加強。好比新的手機增長來電顯示頭像的功能,代碼以下:

```java

classPhone {

publicvoidsendMessage(){    

System.out.println("發短信");        

    }    

publicvoidcall(){    

System.out.println("打電話");        

    }    

publicvoidshowNum(){    

System.out.println("來電顯示號碼");        

    }    

}

//智能手機類

classNewPhoneextendsPhone {

//重寫父類的來電顯示號碼功能,並增長本身的顯示姓名和圖片功能    

publicvoidshowNum(){    

//調用父類已經存在的功能使用super        

super.showNum();        

//增長本身特有顯示姓名和圖片功能        

System.out.println("顯示來電姓名");        

System.out.println("顯示頭像");        

    }    

}

publicclassExtendsDemo06 {

publicstaticvoidmain(String[] args) {    

// 建立子類對象  

NewPhonenp = newNewPhone();  

// 調用父類繼承而來的方法

np.call();

// 調用子類重寫的方法  

np.showNum();  

}    

}

```

**注意事項**

1. 子類方法覆蓋父類方法,必需要保證權限大於等於父類權限。

2. 子類方法覆蓋父類方法,返回值類型、函數名和參數列表都要如出一轍。

 6.4 super 和this

父類空間優先於子類對象產生

在每次建立子類對象時,先初始化父類空間,再建立其子類對象自己。目的在於子類對象中包含了其對應的父類空間,即可以包含其父類的成員,若是父類成員非private修飾,則子類能夠隨意使用父類成員。代碼體如今子類的構造方法調用時,必定先調用父類的構造方法。

super和this的含義

- super :表明父類的存儲空間標識(能夠理解爲父親的引用)。

- this :表明當前對象的引用(誰調用就表明誰)。

super和this的用法

1. 訪問成員

```java

this.成員變量     ‐‐    本類的   

super.成員變量     ‐‐    父類的  

this.成員方法名()   ‐‐    本類的      

super.成員方法名()   ‐‐    父類的

```

示例:

```java

classAnimal {

publicvoideat() {

System.out.println("animal : eat");

    }

}

classCatextendsAnimal {

publicvoideat() {

System.out.println("cat : eat");

    }

publicvoideatTest() {

this.eat();   // this  調用本類的方法

super.eat();  // super 調用父類的方法

    }

}

publicclassExtendsDemo {

publicstaticvoidmain(String[] args) {

Animala = newAnimal();

a.eat();

Catc = newCat();

c.eatTest();

    }

}

輸出結果爲:

animal : eat

cat : eat

animal : eat

```

2. 訪問構造方法

```java

this(...)     ‐‐    本類的構造方法   

super(...)    ‐‐    父類的構造方法

```

- 子類的每一個構造方法中均有默認的super(),調用父類的空參構造。手動調用父類構造會覆蓋默認的super()。

- super() 和 this() 都必須是在構造方法的第一行,因此不能同時出現。

 6.5 抽象類-abstract

父類中的方法,被它的子類們重寫,子類各自的實現都不盡相同。那麼父類的方法聲明和方法主體,只有聲明還有意義,而方法主體則沒有存在的意義了。咱們把沒有方法主體的方法稱爲**抽象方法**。**Java語法規定,包含抽象方法的類就是抽象類**。

 抽象方法 : 沒有方法體的方法。

使用 abstract 關鍵字修飾方法,該方法就成了抽象方法,抽象方法只包含一個方法名,而沒有方法體

格式:

```java

修飾符 abstract 返回值類型 方法名 (參數列表);

```

示例:

```java

publicabstractvoidrun();

```

 抽象類 :包含抽象方法的類。

格式:

```java

abstractclass類名字 {

}

```

示例:

```java

publicabstractclassAnimal {

publicabstractvoidrun();

}

```

抽象的使用:

繼承抽象類的子類必須重寫父類全部的抽象方法。不然,該子類也必須聲明爲抽象類。最終,必須有子類實現該父類的抽象方法,不然,從最初的父類到最終的子類都不能建立對象,失去意義。

```java

publicclassCatextendsAnimal {

publicvoidrun (){

System.out.println("小貓在牆頭走~~~");         

    }

}

publicclassCatTest {

publicstaticvoidmain(String[] args) {   

// 建立子類對象

Catc = newCat();

// 調用run方法

c.run();

   }  

}

輸出結果:

小貓在牆頭走~~~

```

此時的方法重寫,是子類對父類抽象方法的完成實現,咱們將這種方法重寫的操做,也叫作實現方法。

 7 多態

多態 : 是指同一行爲,具備多個不一樣表現形式。

 7.1 多態的體現

多態體現的格式:

```java

父類類型 變量名 = new 子類對象; //父類類型:指子類對象繼承的父類類型,或者實現的父接口類型。

變量名.方法名();

```

當使用多態方式調用方法時,首先檢查父類中是否有該方法,若是沒有,則編譯錯誤;若是有,執行的是子類重寫後方法。

定義父類:

```java

publicabstractclassAnimal { 

publicabstractvoideat(); 

}

```

定義子類:

```java

classCatextendsAnimal { 

publicvoideat() { 

System.out.println("吃魚"); 

    } 

classDogextendsAnimal { 

publicvoideat() { 

System.out.println("吃骨頭"); 

    } 

}

```

定義測試類:

```java

publicclassTest {

publicstaticvoidmain(String[] args) {

// 多態形式,建立對象

Animala1 = newCat(); 

// 調用的是 Cat 的 eat

a1.eat();         

// 多態形式,建立對象

Animala2 = newDog();

// 調用的是 Dog 的 eat

a2.eat();              

    } 

}

```

 7.2 多態的好處

實際開發的過程當中,父類類型做爲方法形式參數,傳遞子類對象給方法,進行方法的調用,更能體現出多態的擴展性與便利。

定義父類:

```java

publicabstractclassAnimal { 

publicabstractvoideat(); 

```

定義子類:

```java

classCatextendsAnimal { 

publicvoideat() { 

System.out.println("吃魚"); 

    } 

classDogextendsAnimal { 

publicvoideat() { 

System.out.println("吃骨頭"); 

    } 

}

```

定義測試類:

```java

publicclassTest {

publicstaticvoidmain(String[] args) {

// 多態形式,建立對象

Catc = newCat(); 

Dogd = newDog();

// 調用showCatEat

showCatEat(c);

// 調用showDogEat

showDogEat(d);

/*

        以上兩個方法, 都可以被showAnimalEat(Animal a)方法所替代

        而執行效果一致

        */

showAnimalEat(c);

showAnimalEat(d);

    }

publicstaticvoidshowCatEat (Catc){

c.eat();

    }

publicstaticvoidshowDogEat (Dogd){

d.eat();

    }

publicstaticvoidshowAnimalEat (Animala){

a.eat();

    }

}

```

因爲多態特性的支持, showAnimalEat方法的Animal類型,是Cat和Dog的父類類型,父類類型接收子類對象,固然能夠把Cat對象和Dog對象,傳遞給方法。

當eat方法執行時,多態規定,執行的是子類重寫的方法,那麼效果天然與showCatEat、showDogEat方法一致,因此showAnimalEat徹底能夠替代以上兩方法。

不只僅是替代,在擴展性方面,不管以後再多的子類出現,咱們都不須要編寫showXxxEat方法了,直接使用showAnimalEat均可以完成。

因此,多態的好處,體如今,可使程序編寫的更簡單,並有良好的擴展。

 7.3  引用類型轉換

多態的轉型分爲向上轉型與向下轉型兩種

 向上轉型

向上轉型 :多態自己是子類類型向父類類型向上轉換的過程,這個過程是默認的。當父類引用指向一個子類對象時,即是向上轉型。

使用格式:

```java

父類類型  變量名 = new 子類類型();

如:Animala = newCat();

```

 向下轉型

向下轉型 :父類類型向子類類型向下轉換的過程,這個過程是強制的。一個已經向上轉型的子類對象,將父類引用轉爲子類引用,可使用強制類型轉換的格式,即是向下轉型。

使用格式:

```java

子類類型 變量名 = (子類類型) 父類變量名;

如:Catc =(Cat) a; 

```

 爲何要轉型

當使用多態方式調用方法時,首先檢查父類中是否有該方法,若是沒有,則編譯錯誤。也就是說,不能調用子類擁有,而父類沒有的方法。編譯都錯誤,更別說運行了。這也是多態給咱們帶來的一點"小麻煩"。因此,想要調用子類特有的方法,必須作向下轉型。

轉型演示,代碼以下:

定義類:

```java

abstractclassAnimal { 

abstractvoideat(); 

classCatextendsAnimal { 

publicvoideat() { 

System.out.println("吃魚"); 

    } 

publicvoidcatchMouse() { 

System.out.println("抓老鼠"); 

    } 

classDogextendsAnimal { 

publicvoideat() { 

System.out.println("吃骨頭"); 

    } 

publicvoidwatchHouse() { 

System.out.println("看家"); 

    } 

}

```

定義測試類:

```java

publicclassTest {

publicstaticvoidmain(String[] args) {

// 向上轉型 

Animala = newCat(); 

a.eat();  // 調用的是 Cat 的 eat               

// 向下轉型 

Catc = (Cat)a;      

c.catchMouse();  // 調用的是 Cat 的 catchMouse        

    } 

}

```

 轉型的異常

轉型的過程當中,一不當心就會遇到這樣的問題,請看以下代碼:

```java

publicclassTest {

publicstaticvoidmain(String[] args) {

// 向上轉型 

Animala = newCat(); 

a.eat();               // 調用的是 Cat 的 eat

// 向下轉型 

Dogd = (Dog)a;      

d.watchHouse();        // 調用的是 Dog 的 watchHouse 【運行報錯】

    } 

}

```

這段代碼能夠經過編譯,可是運行時,卻報出了  `ClassCastException `,類型轉換異常!這是由於,明明建立了Cat類型對象,運行時,固然不能轉換成Dog對象的。這兩個類型並無任何繼承關係,不符合類型轉換的定義。

爲了不`ClassCastException`的發生,Java提供了 ` instanceof `關鍵字,給引用變量作類型的校驗,格式以下:

```java

變量名 instanceof 數據類型

若是變量屬於該數據類型,返回true。

若是變量不屬於該數據類型,返回false。

```

因此,轉換前,咱們最好先作一個判斷,代碼以下:

```java

publicclassTest {

publicstaticvoidmain(String[] args) {

// 向上轉型 

Animala = newCat(); 

a.eat();               // 調用的是 Cat 的 eat

// 向下轉型 

if (a instanceof Cat){

Catc = (Cat)a;      

c.catchMouse();        // 調用的是 Cat 的 catchMouse

        } elseif (a instanceof Dog){

Dogd = (Dog)a;      

d.watchHouse();       // 調用的是 Dog 的 watchHouse

        }

    } 

}

```

 8 接口

接口,是Java語言中一種引用類型,是方法的集合,若是說類的內部封裝了成員變量、構造方法和成員方法,那麼接口的內部主要就是封裝了方法,包含**抽象方法**(JDK 7及之前),**默認方法**和**靜態方法**(JDK 8),**私有方法**(JDK 9)。

接口的定義,它與定義類方式類似,可是使用  interface 關鍵字。它也會被編譯成.class文件,但必定要明確它並非類,而是另一種引用數據類型。

接口的使用,它不能建立對象,可是能夠被實現( implements ,相似於被繼承)。一個實現接口的類(能夠看作是接口的子類),須要實現接口中全部的抽象方法,建立該類對象,就能夠調用方法了,不然它必須是一個抽象類。

定義格式

```java

publicinterface接口名稱 {

// 抽象方法

// 默認方法

// 靜態方法

// 私有方法

}

```

類與接口的關係爲實現關係,即類實現接口,該類能夠稱爲接口的實現類,也能夠稱爲接口的子類。實現的動做相似繼承,格式相仿,只是關鍵字不一樣,實現使用 ` implements` 關鍵字。

非抽象子類實現接口:

1. 必須重寫接口中全部抽象方法。

2. 繼承了接口的默認方法,便可以直接調用,也能夠重寫。

實現格式:

```java

class類名implements 接口名 {

// 重寫接口中抽象方法【必須】

// 重寫接口中默認方法【可選】  

}

```

 8.1 抽象方法

抽象方法:使用 `abstract` 關鍵字修飾,能夠省略,沒有方法體。該方法供子類實現使用。

**抽象方法必須實現。**

定義接口:

```java

publicinterfaceLiveAble {

// 定義抽象方法

publicabstractvoideat();

publicabstractvoidsleep();

}

```

接口實現類:

```java

publicclassAnimalimplementsLiveAble {

    @Override

publicvoideat() {

System.out.println("吃東西");

    }

    @Override

publicvoidsleep() {

System.out.println("晚上睡");

    }

}

```

測試類:

```java

publicclassInterfaceDemo {

publicstaticvoidmain(String[] args) {

// 建立子類對象 

Animala = newAnimal();

// 調用實現後的方法

a.eat();

a.sleep();

    }

}

輸出結果:

吃東西

晚上睡

```

 8.2 默認方法

使用  `default `修飾,不可省略,供子類調用或者子類重寫。

能夠**繼承**,能夠**重寫**,二選一,可是隻能經過實現類的對象來調用。

 繼承默認方法

定義接口:

```java

publicinterfaceLiveAble {

publicdefaultvoidfly(){

System.out.println("天上飛");

    }

}

```

定義實現類:

```java

publicclassAnimalimplementsLiveAble {

// 繼承,什麼都不用寫,直接調用    

}

```

定義測試類:

```java

publicclassInterfaceDemo {

publicstaticvoidmain(String[] args) {

// 建立子類對象 

Animala = newAnimal();

// 調用默認方法

a.fly();

    }

}

輸出結果:

天上飛

```

 重寫默認方法

定義接口:

```java

publicinterfaceLiveAble {

publicdefaultvoidfly(){

System.out.println("天上飛");

    }

}

```

定義實現類:

```java

publicclassAnimalimplementsLiveAble {

    @Override

publicvoidfly() {

System.out.println("自由自在的飛");

    }

}

```

定義測試類:

```java

publicclassInterfaceDemo {

publicstaticvoidmain(String[] args) {

// 建立子類對象 

Animala = newAnimal();

// 調用重寫方法

a.fly();

    }

}

輸出結果:

自由自在的飛

```

 8.3 靜態方法

靜態方法:使用  static 修飾,供接口直接調用。

靜態方法與.class 文件相關,**只能使用接口名調用**,不能夠經過實現類的類名或者實現類的對象調用

定義接口:

```java

publicinterfaceLiveAble {

publicstaticvoidrun(){

System.out.println("跑起來~~~");

    }

}

```

定義實現類:

```java

publicclassAnimalimplementsLiveAble {

// 沒法重寫靜態方法    

}

```

測試類:

```java

publicclassInterfaceDemo {

publicstaticvoidmain(String[] args) {

// Animal.run(); // 【錯誤】沒法繼承方法,也沒法調用

LiveAble.run(); //

    }

}

輸出結果:

跑起來~~~

```

 8.4 私有方法

私有方法:使用  `private` 修飾,供接口中的默認方法或者靜態方法調用。

- 私有方法:只有默認方法能夠調用。

- 私有靜態方法:默認方法和靜態方法能夠調用。

若是一個接口中有多個默認方法,而且方法中有重複的內容,那麼能夠抽取出來,封裝到私有方法中,供默認方法去調用。從設計的角度講,私有的方法是對默認方法和靜態方法的輔助。

示例:

```java

publicinterfaceLiveAble {

defaultvoidfunc(){

func1();

func2();

    }

privatevoidfunc1(){

System.out.println("跑起來~~~");

    }

privatevoidfunc2(){

System.out.println("跑起來~~~");

    }

}

```

 8.5  接口的多實現

在繼承體系中,一個類只能繼承一個父類。而對於接口而言,一個類是能夠實現多個接口的,這叫作接口的多實現。而且,一個類能繼承一個父類,同時實現多個接口。

實現格式:

```java

class類名 [extends 父類名] implements 接口名1,接口名2,接口名3... {

// 重寫接口中抽象方法【必須】

// 重寫接口中默認方法【不重名時可選】  

}

```

 抽象方法多實現

接口中,有多個抽象方法時,實現類必須重寫全部抽象方法。**若是抽象方法有重名的,只須要重寫一次。**

定義多個接口:

```java

interfaceA {

publicabstractvoidshowA();

publicabstractvoidshow();

}

interfaceB {

publicabstractvoidshowB();

publicabstractvoidshow();

}

```

實現:

```java

publicclassCimplementsA,B{

    @Override

publicvoidshowA() {

System.out.println("showA");

    }

    @Override

publicvoidshowB() {

System.out.println("showB");

    }

    @Override

publicvoidshow() {

System.out.println("show");

    }

}

```

 默認方法多實現

接口中,有多個默認方法時,實現類均可繼承使用。**若是默認方法有重名的,必須重寫一次。**

定義多個接口:

```java

interfaceA {

publicdefaultvoidmethodA(){}

publicdefaultvoidmethod(){}

}

interfaceB {

publicdefaultvoidmethodB(){}

publicdefaultvoidmethod(){}

}

```

實現:

```java

publicclassCimplementsA,B{

    @Override

publicvoidmethod() {

System.out.println("method");

    }

}

```

 靜態方法多實現

接口中,存在同名的靜態方法並不會衝突,緣由是隻能經過各自接口名訪問靜態方法。

 優先級的問題

當一個類,既繼承一個父類,又實現若干個接口時,父類中的成員方法與接口中的默認方法重名,子類就近選擇執行父類的成員方法。

定義接口:

```java

interfaceA {

publicdefaultvoidmethodA(){

System.out.println("AAAAAAAAAAAA");

    }

}

```

定義父類:

```java

classD {

publicvoidmethodA(){

System.out.println("DDDDDDDDDDDD");

    }

}

```

定義子類:

```java

classCextendsDimplementsA {

// 未重寫methodA方法  

}

```

定義測試類:

```java

publicclassTest {

publicstaticvoidmain(String[] args) {

Cc = newC();

c.methodA();

    }

}

輸出結果:

DDDDDDDDDDDD

```

 8.6 接口的多繼承

一個接口能繼承另外一個或者多個接口,這和類之間的繼承比較類似。接口的繼承使用  extends 關鍵字,子接口繼承父接口的方法。若是父接口中的默認方法有重名的,那麼子接口須要重寫一次。

定義父接口:

```java

interfaceA {

publicdefaultvoidmethod(){

System.out.println("AAAAAAAAAAAAAAAAAAA");

    }

}

interfaceB {

publicdefaultvoidmethod(){

System.out.println("BBBBBBBBBBBBBBBBBBB");

    }

}

```

定義子接口:

```java

interfaceDextendsA,B{

    @Override

publicdefaultvoidmethod() {

System.out.println("DDDDDDDDDDDDDD");

    }

}

```

 8.7 主要事項

1. 子接口重寫默認方法時,default關鍵字能夠保留。

2. 子類重寫默認方法時,default關鍵字不能夠保留。

3.**接口中,沒法定義成員變量,可是能夠定義常量,其值不能夠改變,默認使用 `public static final`修飾。**

4. 接口中,沒有構造方法,不能建立對象。

5. 接口中,沒有靜態代碼塊。

 9  static關鍵字

關於  static 關鍵字的使用,它能夠用來修飾的**成員變量**和**成員方法**,被修飾的成員是屬於類的,而不是單單是屬

於某個對象的。也就是說,既然屬於類,就能夠不靠建立對象來調用了。

 9.1 類變量

當  static 修飾**成員變量**時,該變量稱爲**類變量**。該類的每一個對象都共享同一個類變量的值。任何對象均可以更改該類變量的值,但也能夠在不建立該類的對象的狀況下對類變量進行操做。

格式:

```java

static 數據類型 變量名;

```

示例:

建立Student類

```java

publicclassStudent {

privateintid;

privateStringname;

privateintage;

staticStringroom;

privatestaticintidCounter = 0; //學號計數器,每當new了一個新對象的時候,計數器++

publicStudent(){

this.id = ++idCounter;

    }

publicStudent(Stringname,intage) {

this.id = ++idCounter;

this.name = name;

this.age = age;

    }

publicintgetId() {

return id;

    }

publicvoidsetId(intid) {

this.id = id;

    }

publicStringgetName() {

return name;

    }

publicvoidsetName(Stringname) {

this.name = name;

    }

publicintgetAge() {

return age;

    }

publicvoidsetAge(intage) {

this.age = age;

    }

}

```

調用:

```java

publicclassStaticDemo {

publicstaticvoidmain(String[] args) {

// 首先設置一下教室,這是靜態的東西,應該經過類名稱進行調用

Student.room = "101教室";

Studentstu1 = newStudent("xiaoming",18);

System.out.println("id:"+ stu1.getId()+",姓名:"+ stu1.getName()+",年齡:"+stu1.getAge()+",教室:"+Student.room);

System.out.println("=====================");

Studentstu2 = newStudent("xiaohong",19);

System.out.println("id:"+ stu2.getId()+",姓名:"+ stu2.getName()+",年齡:"+stu2.getAge()+",教室:"+Student.room);

System.out.println("=====================");

Studentstu3 = newStudent("xiaowang",22);

System.out.println("id:"+ stu3.getId()+",姓名:"+ stu3.getName()+",年齡:"+stu3.getAge()+",教室:"+Student.room);

System.out.println("=====================");

    }

}

```

**類變量的修改還調用通常直接使用類名**

 9.2  靜態方法

當 static 修飾成員方法時,該方法稱爲**類方法** 。**靜態方法在聲明中有 static ,建議使用類名來調用,而不須要建立類的對象。**調用方式很是簡單。

使用 static關鍵字修飾的成員方法,習慣稱爲**靜態方法**。

格式:

```java

修飾符 static 返回值類型 方法名 (參數列表){

// 執行語句     

}

```

示例: 在Student類中定義靜態方法

```java

publicstaticvoidshowNum() {

System.out.println("num:" +  numberOfStudent);

}

```

調用格式:

被static修飾的成員能夠而且**建議經過類名直接訪問**。雖然也能夠經過對象名訪問靜態成員,緣由即多個對象均屬於一個類,共享使用同一個靜態成員,可是不建議,會出現警告信息。

格式:

```java

// 訪問類變量

類名.類變量名;

// 調用靜態方法

類名.靜態方法名(參數);

```

示例:

```java

//訪問靜態變量(類變量)

System.out.println(Student.room);

//訪問靜態方法

Student.showNum();

```

**靜態方法調用的注意事項:**

- 靜態方法能夠直接訪問類變量和靜態方法。

- 靜態方法 不能直接訪問普通成員變量或成員方法。反之成員方法能夠直接訪問類變量或靜態方法。

- 靜態方法中,不能使用 this關鍵字。

 9.3  靜態原理圖解

static 修飾的內容:

- 是隨着類的加載而加載的,且只加載一次。

- 存儲於一塊固定的內存區域(靜態區),因此,能夠直接被類名調用。

- 它優先於對象存在,因此,能夠被全部對象共享。

![靜態的內存圖](https://foochane.cn/images/20...

 9.4  靜態代碼塊

靜態代碼塊 :定義在成員位置,使用static修飾的代碼塊{ }。

- 位置:類中方法外。

- 執行:**隨着類的加載而執行且執行一次,優先於 main方法和構造方法的執行**。

格式:

```java

publicclassClassName{

static {

// 執行語句

  }

}

```

示例:

```java

publicclassPerson {

static {

System.out.println("靜態代碼塊執行!");

    }

publicPerson() {

System.out.println("構造方法執行!");

    }

}

```

調用Person類

```java

/*

靜態代碼塊特色:當第一次用到本類時,靜態代碼塊執行惟一的一次。

靜態內容老是優先於非靜態,因此靜態代碼塊比構造方法先執行。

靜態代碼塊的典型用途:用來一次性地對靜態成員變量進行賦值。

 */

publicclassDemo04Static {

publicstaticvoidmain(String[] args) {

//靜態代碼塊先執行,且只執行一次,構造方法執行了兩次

Personone = newPerson();

Persontwo = newPerson();

    }

}

```

 10  final關鍵字

學習了繼承後,咱們知道,子類能夠在父類的基礎上改寫父類內容,好比,方法重寫。那麼咱們能不能隨意的繼承API中提供的類,改寫其內容呢?顯然這是不合適的。爲了不這種隨意改寫的狀況,Java提供了`final `關鍵字,用於修飾不可改變內容。

**`final `: 不可改變。能夠用於修飾類、方法和變量。**

- 類:被修飾的類,不能被繼承。

- 方法:被修飾的方法,不能被重寫。

- 變量:被修飾的變量,不能被從新賦值。

 10.1 修飾類

格式以下:

```java

finalclass類名 {

}

```

查詢 API發現像  public final class String 、 public final class Math 、 public final class Scanner等,不少咱們學習過的類,都是被final修飾的,目的就是供咱們使用,而不讓咱們因此改變其內容。

 10.2 修飾方法

格式以下:

```java

修飾符 final 返回值類型 方法名(參數列表){

//方法體

}

```

**重寫被  final 修飾的方法,編譯時就會報錯。**

 10.3 修飾變量

 局部變量—基本類型

基本類型的局部變量,被final修飾後,只能賦值一次,不能再更改。代碼以下:

```java

publicclassFinalDemo1 {

publicstaticvoidmain(String[] args) {

// 聲明變量,使用final修飾

finalinta;

// 第一次賦值

        a = 10;

// 第二次賦值

        a = 20; // 報錯,不可從新賦值

// 聲明變量,直接賦值,使用final修飾

finalintb = 10;

// 第二次賦值

        b = 20; // 報錯,不可從新賦值

    }

}

```

  局部變量—引用類型

引用類型的局部變量,被final修飾後,只能指向一個對象,地址不能再更改。可是不影響對象內部的成員變量值的修改,代碼以下:

```java

publicclassFinalDemo2 {

publicstaticvoidmain(String[] args) {

// 建立 User 對象

finalUseru = newUser();

// 建立 另外一個 User對象

        u = newUser(); // 報錯,指向了新的對象,地址值改變。

// 調用setName方法

u.setName("張三"); // 能夠修改

    }

}

```

 成員變量

成員變量涉及到初始化的問題,初始化方式有兩種,只能二選一:

- 顯示初始化:

```java

publicclassUser {

finalStringUSERNAME = "張三";

privateintage;

}

```

- 構造方法初始化:

```java

publicclassUser {

finalStringUSERNAME ;

privateintage;

publicUser(Stringusername, intage) {

this.USERNAME = username;

this.age = age;

    }

}

```

**被final修飾的常量名稱,通常都有書寫規範,全部字母都大寫。**

  11 權限修飾符

在Java中提供了四種訪問權限,使用不一樣的訪問權限修飾符修飾時,被修飾的內容會有不一樣的訪問權限,

- public :公共的。

- protected :受保護的

- default :默認的

- private :私有的

不一樣權限的訪問能力:

| 類                     | public | protected | default(空的) | private |

| ---------------------- | ------ | --------- | --------------- | ------- |

| 同一類中               | YES    | YES       | YES             | YES     |

| 同一包中(子類與無關類) | YES    | YES       | YES             | NO      |

| 不一樣包的子類           | YES    | YES       | NO              | NO      |

| 不一樣包中的無關類       | YES    | NO        | NO              | NO      |

可見,public具備最大權限。private則是最小權限。

編寫代碼時,若是沒有特殊的考慮,建議這樣使用權限:

- 成員變量使用 private ,隱藏細節。

- 構造方法使用 public ,方便建立對象。

- 成員方法使用 public ,方便調用方法。

**注意:不加權限修飾符,其訪問能力與default修飾符相同**

 12 內部類

將一個類A定義在另外一個類B裏面,裏面的那個類A就稱爲內部類,B則稱爲外部類。

 12.1 成員內部類

成員內部類 :定義在類中方法外的類。

定義格式:

```java

class外部類 {

class內部類{

    }

}

```

在描述事物時,若一個事物內部還包含其餘事物,就可使用內部類這種結構。好比,汽車類 Car 中包含發動機類 Engine ,這時, Engine 就可使用內部類來描述,定義在成員位置。

代碼舉例:

```java

classCar { //外部類

classEngine { //內部類

    }

}

```

訪問特色

- 內部類能夠直接訪問外部類的成員,包括私有成員。

- 外部類要訪問內部類的成員,必需要創建內部類的對象。

建立內部類對象格式:

```java

外部類名.內部類名 對象名 = new 外部類型().new 內部類型();

```

訪問演示,代碼以下:

定義類:

```java

publicclassPerson {

privatebooleanlive = true;

classHeart {

publicvoidjump() {

// 直接訪問外部類成員

if (live) {

System.out.println("心臟在跳動");

            } else {

System.out.println("心臟不跳了");

            }

        }

    }

publicbooleanisLive() {

return live;

    }

publicvoidsetLive(booleanlive) {

this.live = live;

    }

}

```

定義測試類:

```java

publicclassInnerDemo {

publicstaticvoidmain(String[] args) {

// 建立外部類對象

Personp  = newPerson();

// 建立內部類對象

Heartheart = p.newHeart();

// 調用內部類方法

heart.jump();

// 調用外部類方法

p.setLive(false);

// 調用內部類方法

heart.jump();

    }

}

輸出結果:

心臟在跳動

心臟不跳了

```

內部類仍然是一個獨立的類,在編譯以後會內部類會被編譯成獨立的 .class文件,可是前面冠之外部類的類名和`$`符號 。

好比,`Person$Heart.class`

內部類重名變量訪問:

```java

publicclassOuter {

intnum = 10;

publicclassInner{

intnum = 20;

publicvoidmethodInner(){

intnum = 30;

System.out.println(num);

System.out.println(this.num);

System.out.println(Outer.this.num);

        }

    }

publicstaticvoidmain(String[] args) {

Outer.Innerinner =  newOuter().new Inner();

inner.methodInner();

    }

}

輸出:

30

20

10

```

 12.2  匿名內部類

匿名內部類 :是內部類的簡化寫法。它的本質是一個 帶具體實現的 父類或者父接口的 匿名的 子類對象。開發中,最經常使用到的內部類就是匿名內部類了。

匿名內部類必須繼承一個父類或者實現一個父接口。

格式:

```java

new 父類名或者接口名(){

// 方法重寫

    @Override

publicvoidmethod() {

// 執行語句

    }

};

```

使用方式

以接口爲例,匿名內部類的使用,代碼以下:

定義接口:

```java

publicabstractclassFlyAble{

publicabstractvoidfly();

}

```

建立匿名內部類,並調用:

```java

publicclassInnerDemo {

publicstaticvoidmain(String[] args) {

/*

        1.等號右邊:是匿名內部類,定義並建立該接口的子類對象

        2.等號左邊:是多態賦值,接口類型引用指向子類對象

        */

FlyAblef = newFlyAble(){

publicvoidfly() {

System.out.println("我飛了~~~");

            }

        };

//調用 fly方法,執行重寫後的方法

f.fly();

    }

}

```

一般在方法的形式參數是接口或者抽象類時,也能夠將匿名內部類做爲參數傳遞。代碼以下:

```java

publicclassInnerDemo2 {

publicstaticvoidmain(String[] args) {

/*

        1.等號右邊:定義並建立該接口的子類對象

        2.等號左邊:是多態,接口類型引用指向子類對象

       */

FlyAblef = newFlyAble(){

publicvoidfly() {

System.out.println("我飛了~~~");

            }

        };

// 將f傳遞給showFly方法中

showFly(f);

    }

publicstaticvoidshowFly(FlyAblef) {

f.fly();

    }

}

```

以上兩步,也能夠簡化爲一步,代碼以下:

```java

publicclassInnerDemo3 {

publicstaticvoidmain(String[] args) {           

/*

       建立匿名內部類,直接傳遞給showFly(FlyAble f) 

        */

showFly( newFlyAble(){

publicvoidfly() {

System.out.println("我飛了~~~");

            }

        });

    }

publicstaticvoidshowFly(FlyAblef) {

f.fly();

    }

}

```

 13 引用類型用法總結

實際的開發中,引用類型的使用很是重要,也是很是廣泛的。咱們能夠在理解基本類型的使用方式基礎上,進一步去掌握引用類型的使用方式。基本類型能夠做爲成員變量、做爲方法的參數、做爲方法的返回值,那麼固然引用類型也是能夠的。

 13.1 class 做爲成員變量

在定義一個類Role(遊戲角色)時,代碼以下:

```java

classRole {

intid; // 角色id  

intblood; // 生命值  

Stringname; // 角色名稱  

}

```

使用 int 類型表示 角色id和生命值,使用 String 類型表示姓名。此時, String 自己就是引用類型,因爲使用的方式相似常量,因此每每忽略了它是引用類型的存在。若是咱們繼續豐富這個類的定義,給 Role 增長武器,穿戴裝備等屬性,咱們將如何編寫呢?

定義武器類,將增長攻擊能力:

```java

classWeapon {

String name; // 武器名稱   

int hurt; // 傷害值

}

```

定義穿戴盔甲類,將增長防護能力,也就是提高生命值:

```java

classArmour {

String name;// 裝備名稱  

int protect;// 防護值 

}

```

定義角色類:

```java

classRole {

int id;

int blood;

String name;

// 添加武器屬性

Weapon wp;

// 添加盔甲屬性

Armour ar;

// 提供get/set方法

publicWeapongetWp() {

return wp;

    }

publicvoidsetWeapon(Weaponwp) {

this.wp = wp;

    }

publicArmourgetArmour() {

return ar;

    }

publicvoidsetArmour(Armourar) {

this.ar = ar;

    }

// 攻擊方法

publicvoidattack(){

System.out.println("使用"+ wp.getName() +", 形成"+wp.getHurt()+"點傷害"); 

    }

// 穿戴盔甲

publicvoidwear(){

// 增長防護,就是增長blood值

this.blood += ar.getProtect();

System.out.println("穿上"+ar.getName()+", 生命值增長"+ar.getProtect());

    } 

}

```

測試類:

```java

publicclassTest {

publicstaticvoidmain(String[] args) {  

// 建立Weapon 對象     

Weaponwp = newWeapon("屠龍刀" , 999999);        

// 建立Armour 對象  

Armourar = newArmour("麒麟甲",10000);  

// 建立Role 對象  

Roler = newRole();        

// 設置武器屬性  

r.setWeapon(wp);   

// 設置盔甲屬性   

r.setArmour(ar);  

// 攻擊  

r.attack();  

// 穿戴盔甲

r.wear();  

   }  

}

輸出結果:

使用屠龍刀,形成999999點傷害

穿上麒麟甲 ,生命值增長10000

```

類做爲成員變量時,對它進行賦值的操做,實際上,是賦給它該類的一個對象。

 13.2 interface 做爲成員變量

接口是對方法的封裝,對應遊戲當中,能夠看做是擴展遊戲角色的技能。因此,若是想擴展更強大技能,咱們在Role 中,能夠增長接口做爲成員變量,來設置不一樣的技能。

定義接口:

```java

// 法術攻擊

publicinterfaceFaShuSkill {

publicabstractvoidfaShuAttack();

}

```

定義角色類:

```java

publicclassRole {

FaShuSkillfs;

publicvoidsetFaShuSkill(FaShuSkillfs) {

this.fs = fs;

    }

// 法術攻擊

publicvoidfaShuSkillAttack(){

System.out.print("發動法術攻擊:");

fs.faShuAttack();

System.out.println("攻擊完畢");

    }

}

```

定義測試類:

```java

publicclassTest {

publicstaticvoidmain(String[] args) {

// 建立遊戲角色

Rolerole = newRole();

// 設置角色法術技能

role.setFaShuSkill(newFaShuSkill() {

            @Override

publicvoidfaShuAttack() {

System.out.println("縱橫天下");

            }

        });

// 發動法術攻擊

role.faShuSkillAttack();

// 更換技能

role.setFaShuSkill(newFaShuSkill() {

            @Override

publicvoidfaShuAttack() {

System.out.println("逆轉乾坤");

            }

        });

// 發動法術攻擊

role.faShuSkillAttack();

    }    

}

輸出結果:

發動法術攻擊:縱橫天下

攻擊完畢

發動法術攻擊:逆轉乾坤

攻擊完畢

```

咱們使用一個接口,做爲成員變量,以便隨時更換技能,這樣的設計更爲靈活,加強了程序的擴展性。

接口做爲成員變量時,對它進行賦值的操做,實際上,是賦給它該接口的一個子類對象。

 13.3  interface 做爲方法參數和返回值類型

當接口做爲方法的參數時,須要傳遞什麼呢?當接口做爲方法的返回值類型時,須要返回什麼呢?對,其實都是它的子類對象。  ArrayList 類咱們並不陌生,查看API咱們發現,實際上,它是  java.util.List 接口的實類。因此,當咱們看見 List 接口做爲參數或者返回值類型時,固然能夠將 ArrayList 的對象進行傳遞或返回。

請觀察以下方法:獲取某集合中全部的偶數。

定義方法:

```java

publicstaticList<Integer> getEvenNum(List<Integer> list) {

// 建立保存偶數的集合

ArrayList<Integer> evenList = newArrayList<>();

// 遍歷集合list,判斷元素爲偶數,就添加到evenList中

for (inti = 0; i < list.size(); i++) {

Integerinteger = list.get(i);

if (integer % 2 == 0) {

evenList.add(integer);

        }

    }

/*

   返回偶數集合

   由於getEvenNum方法的返回值類型是List,而ArrayList是List的子類, 

   因此evenList能夠返回 

   */

return evenList;

}

```

調用方法:

```java

publicclassTest {

publicstaticvoidmain(String[] args) {

// 建立ArrayList集合,並添加數字

ArrayList<Integer> srcList = newArrayList<>();

for (inti = 0; i < 10; i++) {

srcList.add(i);

        }

/*

       獲取偶數集合  

       由於getEvenNum方法的參數是List,而ArrayList是List的子類,  

       因此srcList能夠傳遞  

       */

Listlist = getEvenNum(srcList);

System.out.println(list);

    }

}

```

接口做爲參數時,傳遞它的子類對象。

接口做爲返回值類型時,返回它的子類對象。

 14 遞歸

 14.1 概述

***遞歸**:指在當前方法內調用本身的這種現象。

***遞歸的分類:**

- 遞歸分爲兩種,直接遞歸和間接遞歸。

- 直接遞歸稱爲方法自身調用本身。

- 間接遞歸能夠A方法調用B方法,B方法調用C方法,C方法調用A方法。

***注意事項**:

- 遞歸必定要有條件限定,保證遞歸可以中止下來,不然會發生棧內存溢出。

- 在遞歸中雖然有限定條件,可是遞歸次數不能太多。不然也會發生棧內存溢出。

- 構造方法,禁止遞歸

```java

publicclassDemo01DiGui {

publicstaticvoidmain(String[] args) {

// a();

b(1);

    }

/*

     * 3.構造方法,禁止遞歸

     * 編譯報錯:構造方法是建立對象使用的,不能讓對象一直建立下去

     */

publicDemo01DiGui() {

//Demo01DiGui();

    }

/*

     * 2.在遞歸中雖然有限定條件,可是遞歸次數不能太多。不然也會發生棧內存溢出。

     * 4993

     *  Exception in thread "main" java.lang.StackOverflowError

     */

privatestaticvoidb(inti) {

System.out.println(i);

//添加一個遞歸結束的條件,i==5000的時候結束

if(i==5000){

return;//結束方法

        }

b(++i);

    }

/*

     * 1.遞歸必定要有條件限定,保證遞歸可以中止下來,不然會發生棧內存溢出。 Exception in thread "main"

     * java.lang.StackOverflowError

     */

privatestaticvoida() {

System.out.println("a方法");

a();

    }

}

```

 14.2 遞歸累加求和  

 計算1 ~ n的和

**分析**:num的累和 = num + (num-1)的累和,因此能夠把累和的操做定義成一個方法,遞歸調用。

**實現代碼**:

```java

publicclassDiGuiDemo {

publicstaticvoidmain(String[] args) {

//計算1~num的和,使用遞歸完成

intnum = 5;

// 調用求和的方法

intsum = getSum(num);

// 輸出結果

System.out.println(sum);

    }

/*

      經過遞歸算法實現.

      參數列表:int 

      返回值類型: int 

    */

publicstaticintgetSum(intnum) {

/* 

           num爲1時,方法返回1,

           至關因而方法的出口,num總有是1的狀況

        */

if(num == 1){

return1;

        }

/*

          num不爲1時,方法返回 num +(num-1)的累和

          遞歸調用getSum方法

        */

return num + getSum(num-1);

    }

}

```

 代碼執行圖解

![遞歸累和](https://raw.githubusercontent...

> 小貼士:遞歸必定要有條件限定,保證遞歸可以中止下來,次數不要太多,不然會發生棧內存溢出。

 14.3 遞歸求階乘

***階乘**:全部小於及等於該數的正整數的積。

```java

n的階乘:n! = n * (n-1) *...* 3 * 2 * 1

```

**分析**:這與累和相似,只不過換成了乘法運算,學員能夠本身練習,須要注意階乘值符合int類型的範圍。

```Java

推理得出:n! = n * (n-1)!

```

**代碼實現**:

```java

publicclassDiGuiDemo {

//計算n的階乘,使用遞歸完成

publicstaticvoidmain(String[] args) {

intn = 3;

// 調用求階乘的方法

intvalue = getValue(n);

// 輸出結果

System.out.println("階乘爲:"+ value);

    }

/*

      經過遞歸算法實現.

      參數列表:int 

      返回值類型: int 

    */

publicstaticintgetValue(intn) {

// 1的階乘爲1

if (n == 1) {

return1;

        }

/*

          n不爲1時,方法返回 n! = n*(n-1)!

          遞歸調用getValue方法

        */

return n * getValue(n - 1);

    }

}

```

 14.4 遞歸打印多級目錄

**分析**:多級目錄的打印,就是當目錄的嵌套。遍歷以前,無從知道到底有多少級目錄,因此咱們仍是要使用遞歸實現。

**代碼實現**:

```java  

publicclassDiGuiDemo2 {

publicstaticvoidmain(String[] args) {

// 建立File對象

Filedir  = newFile("D:\\aaa");

// 調用打印目錄方法

printDir(dir);

    }

publicstaticvoidprintDir(Filedir) {

// 獲取子文件和目錄

File[] files = dir.listFiles();

// 循環打印

/*

          判斷:

          當是文件時,打印絕對路徑.

          當是目錄時,繼續調用打印目錄的方法,造成遞歸調用.

        */

for (Filefile: files) {

// 判斷

if (file.isFile()) {

// 是文件,輸出文件絕對路徑

System.out.println("文件名:"+ file.getAbsolutePath());

            } else {

// 是目錄,輸出目錄絕對路徑

System.out.println("目錄:"+file.getAbsolutePath());

// 繼續遍歷,調用printDir,造成遞歸

printDir(file);

            }

        }

    }

}

```

 14.5 綜合案例   

 文件搜索   

搜索`D:\aaa` 目錄中的`.java` 文件。

**分析**:

1. 目錄搜索,沒法判斷多少級目錄,因此使用遞歸,遍歷全部目錄。

2. 遍歷目錄時,獲取的子文件,經過文件名稱,判斷是否符合條件。

**代碼實現**:

```java

publicclassDiGuiDemo3 {

publicstaticvoidmain(String[] args) {

// 建立File對象

Filedir  = newFile("D:\\aaa");

// 調用打印目錄方法

printDir(dir);

    }

publicstaticvoidprintDir(Filedir) {

// 獲取子文件和目錄

File[] files = dir.listFiles();

// 循環打印

for (Filefile: files) {

if (file.isFile()) {

// 是文件,判斷文件名並輸出文件絕對路徑

if (file.getName().endsWith(".java")) {

System.out.println("文件名:" + file.getAbsolutePath());

                }

            } else {

// 是目錄,繼續遍歷,造成遞歸

printDir(file);

            }

        }

    }

}

```

 文件過濾器優化

`java.io.FileFilter`是一個接口,是File的過濾器。 該接口的對象能夠傳遞給File類的`listFiles(FileFilter)` 做爲參數, 接口中只有一個方法。

`boolean accept(File pathname)  ` :測試pathname是否應該包含在當前File目錄中,符合則返回true。

**分析**:

1. 接口做爲參數,須要傳遞子類對象,重寫其中方法。咱們選擇匿名內部類方式,比較簡單。

2.`accept`方法,參數爲File,表示當前File下全部的子文件和子目錄。保留住則返回true,過濾掉則返回false。保留規則:

1. 要麼是.java文件。

2. 要麼是目錄,用於繼續遍歷。

3. 經過過濾器的做用,`listFiles(FileFilter)`返回的數組元素中,子文件對象都是符合條件的,能夠直接打印。

**代碼實現:**

```java

publicclassDiGuiDemo4 {

publicstaticvoidmain(String[] args) {

Filedir = newFile("D:\\aaa");

printDir2(dir);

    }

publicstaticvoidprintDir2(Filedir) {

// 匿名內部類方式,建立過濾器子類對象

File[] files = dir.listFiles(newFileFilter() {

            @Override

publicbooleanaccept(Filepathname) {

returnpathname.getName().endsWith(".java")||pathname.isDirectory();

            }

        });

// 循環打印

for (Filefile: files) {

if (file.isFile()) {

System.out.println("文件名:" + file.getAbsolutePath());

            } else {

printDir2(file);

            }

        }

    }

}      

```

 Lambda優化

**分析:**`FileFilter`是隻有一個方法的接口,所以能夠用lambda表達式簡寫。

lambda格式:

```java

()->{ }

```

**代碼實現:**

```java

publicstaticvoidprintDir3(File dir) {

// lambda的改寫

File[] files = dir.listFiles(f ->{ 

returnf.getName().endsWith(".java") || f.isDirectory(); 

    });

// 循環打印

for (Filefile: files) {

if (file.isFile()) {

System.out.println("文件名:" + file.getAbsolutePath());

        } else {

printDir3(file);

        }

    }

}

```

相關文章
相關標籤/搜索