final關鍵字,權限修飾符、內部類

final關鍵字

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

final關鍵字能夠修飾:學習

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

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

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

修飾類

final修飾的類:不能被繼承。對象

格式blog

1 final class 類名 {
2     //
3 }

修飾方法

格式繼承

1 修飾符 final 返回值類型 方法名(參數列表){     
2     //方法體 
3 }

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

修飾變量

修飾局部變量

局部變量爲基本類型

基本類型的局部變量,被final修飾後,只能賦值一次,不能再更改內存

 1 public class Demo01Final {
 2 
 3     public static void main(String[] args) {
 4         int num1 = 10;
 5         System.out.println(num1); // 10
 6         num1 = 20;
 7         System.out.println(num1); // 20
 8 
 9         // 一旦使用final用來修飾局部變量,那麼這個變量就不能進行更改。
10         // 「一次賦值,終生不變」
11         final int num2 = 200;
12         System.out.println(num2); // 200
13 
14         // num2 = 250; // 錯誤寫法!不能改變!
15         // num2 = 200; // 錯誤寫法!
16 
17         // 正確寫法!只要保證有惟一一次賦值便可
18         final int num3;
19         num3 = 30;
20     }
21 }
局部變量爲基本類型的示例

被final修飾的兩種局部變量比較:

 1 // 第一種:編譯報錯
 2 final int c = 0; 
 3 for (int i = 0; i < 10; i++) {     
 4     c = i;     
 5     System.out.println(c); 
 6 }
 7 
 8 
 9 ----------------------------------------
10 // 第二種:不報錯
11 // 想當與每次都從新定義了一個c變量
12 for (int i = 0; i < 10; i++) {     
13     final int c = i;     
14     System.out.println(c); 
15 }
View Code

局部變量爲引用類型

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

 1 public class Student {
 2 
 3     private String name;
 4 
 5     public Student() {
 6     }
 7 
 8     public Student(String name) {
 9         this.name = name;
10     }
11 
12     public String getName() {
13         return name;
14     }
15 
16     public void setName(String name) {
17         this.name = name;
18     }
19 }
20 
21 
22 ---------------------------------------------------------
23 public class Demo01Final {
24 
25     public static void main(String[] args) {
26 
27         // 對於基本類型來講,不可變說的是變量當中的數據不可改變
28         // 對於引用類型來講,不可變說的是變量當中的地址值不可改變
29         Student stu1 = new Student("趙麗穎");
30         System.out.println(stu1);
31         System.out.println(stu1.getName()); // 趙麗穎
32         stu1 = new Student("霍建華");
33         System.out.println(stu1);
34         System.out.println(stu1.getName()); // 霍建華
35         System.out.println("===============");
36 
37         final Student stu2 = new Student("高圓圓");
38         // 錯誤寫法!final的引用類型變量,其中的地址不可改變
39         // stu2 = new Student("趙又廷");
40         System.out.println(stu2.getName()); // 高圓圓
41         stu2.setName("高圓圓圓圓圓圓");
42         System.out.println(stu2.getName()); // 高圓圓圓圓圓圓
43     }
44 }
View Code

修飾成員變量

對於成員變量來講,若是使用final關鍵字修飾,那麼這個變量也照樣是不可變。

1. 因爲成員變量具備默認值,因此用了final以後必須手動賦值,不會再給默認值了。

2. 對於final的成員變量,要麼使用直接賦值,要麼經過構造方法賦值。兩者選其一。

3. 若是沒有對變量直接賦值。那麼必須保證類當中全部重載的構造方法,都最終會對final的成員變量進行賦值。

 1 public class Person {
 2 
 3     private final String name/* = "鹿晗"*/;
 4 
 5     public Person() {
 6         name = "關曉彤";
 7     }
 8 
 9     public Person(String name) {
10         this.name = name;
11     }
12 
13     public String getName() {
14         return name;
15     }
16 
17     // set方法就無效了,並且this.name這一行會直接報錯,final修飾後其變量值就不可在變
18     // public void setName(String name) {
19     //     this.name = name;
20     // }
21 }
View Code

權限修飾符

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

public:公共的。

protected:受保護的

default:默認的

private:私有的

權限大小比較

 public  >   protected   >   (default)   >   private

  public  protected   (default)   private
同一個類(我本身) Yes Yes Yes Yes
同一個包(我兒子【子類】或我鄰居【無關類】) Yes Yes Yes No
不一樣包子類(我兒子) Yes Yes No No
不一樣包非子類(陌生人) Yes No No No

注意事項:(default)並非關鍵字「default」,而是根本不寫。

內部類

若是一個事物的內部包含另外一個事物,那麼這就是一個類內部包含另外一個類。例如:身體和心臟的關係。又如:汽車和發動機的關係。

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

成員內部類

成員內部類定義

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

語法

1 修飾符 class 外部類名稱 {
2     修飾符 class 內部類名稱 {
3         // ...
4     }
5     // ...
6 }
 1  // 外部類
 2 public class Body {
 3 
 4     // 成員內部類
 5     public class Heart { 
 6 
 7         // 內部類的方法
 8         public void beat() {
 9             System.out.println("心臟跳動:蹦蹦蹦!");
10             System.out.println("我叫:" + name); // 正確寫法!
11         }
12 
13     }
14 
15     // 外部類的成員變量
16     private String name;
17 
18     // 外部類的方法
19     public void methodBody() {
20         System.out.println("外部類的方法");
21         new Heart().beat();
22     }
23 
24     public String getName() {
25         return name;
26     }
27 
28     public void setName(String name) {
29         this.name = name;
30     }
31 }
內部類定義

在定義內部類的時候,若是內部類的成員變量和外部重名的時候,範圍外部類成員變量:外部類名稱.this.外部類成員變量名

 1 // 若是出現了重名現象,那麼格式是:外部類名稱.this.外部類成員變量名
 2 public class Outer {
 3 
 4     int num = 10; // 外部類的成員變量
 5 
 6     public class Inner /*extends Object*/ {
 7 
 8         int num = 20; // 內部類的成員變量
 9 
10         public void methodInner() {
11             int num = 30; // 內部類方法的局部變量
12             System.out.println(num); // 局部變量,就近原則
13             System.out.println(this.num); // 內部類的成員變量
14             System.out.println(Outer.this.num); // 外部類的成員變量
15         }
16     }
17 }
18 
19 
20 ---------------------------------------------------------------------------------
21 public class Demo02InnerClass {
22 
23     public static void main(String[] args) {
24         // 外部類名稱.內部類名稱 對象名 = new 外部類名稱().new 內部類名稱();
25         Outer.Inner obj = new Outer().new Inner();
26         obj.methodInner();
27     }
28 }
View Code

成員內部類的使用

方法一:間接方式:在外部類的方法當中,使用內部類;而後main只是調用外部類的方法。

方法二:直接方式,公式:類名稱 對象名 = new 類名稱();

【外部類名稱.內部類名稱 對象名 = new 外部類名稱().new 內部類名稱();】

 1 public class Body { // 外部類
 2 
 3     public class Heart { // 成員內部類
 4 
 5         // 內部類的方法
 6         public void beat() {
 7             System.out.println("心臟跳動:蹦蹦蹦!");
 8             System.out.println("我叫:" + name); // 正確寫法!
 9         }
10 
11     }
12 
13     // 外部類的成員變量
14     private String name;
15 
16     // 外部類的方法
17     public void methodBody() {
18         System.out.println("外部類的方法");
19 
20         // 外部類想要訪問內部類須要先建立對象
21         new Heart().beat();
22     }
23 
24     public String getName() {
25         return name;
26     }
27 
28     public void setName(String name) {
29         this.name = name;
30     }
31 }
32 
33 
34 ---------------------------------------------------
35     public static void main(String[] args) {
36         Body body = new Body(); // 外部類的對象
37         // 經過外部類的對象,調用外部類的方法,裏面間接在使用內部類Heart
38         // 這裏雖然沒有new內部類,可是在外部類中訪問方法的時候已經new了
39         body.methodBody();
40         System.out.println("=====================");
41 
42         // 按照公式寫:
43         Body.Heart heart = new Body().new Heart();
44         heart.beat();
45     }
View Code

局部內部類【重點】

若是一個類是定義在一個方法內部的,那麼這就是一個局部內部類。

「局部」:只有當前所屬的方法才能使用它,出了這個方法外面就不能用了。

語法

1 修飾符 class 外部類名稱 {
2     修飾符 返回值類型 外部類方法名稱(參數列表) {
3         class 局部內部類名稱 {
4             // ...
5         }
6     }
7 }

局部內部類的權限修飾符:

1. 外部類:public / (default)

2. 成員內部類:public / protected / (default) / private

3. 局部內部類:什麼都不能寫

 1 class Outer {
 2 
 3     public void methodOuter() {
 4         // 局部內部類
 5         class Inner { 
 6             int num = 10;
 7             public void methodInner() {
 8                 System.out.println(num); // 10
 9             }
10         }
11 
12         Inner inner = new Inner();
13         inner.methodInner();
14     }
15 }
16 
17 
18 ------------------------------------------------
19 public class DemoMain {
20 
21     public static void main(String[] args) {
22         Outer obj = new Outer();
23         obj.methodOuter();
24     }
25 }
代碼示例

局部內部類,若是但願訪問所在方法的局部變量,那麼這個局部變量必須是【有效final的】

備註:從Java 8+開始,只要局部變量事實不變,那麼final關鍵字能夠省略。【只要在代碼中沒有在更改局部變量的值】

緣由:

1. new出來的對象在堆內存當中。

2. 局部變量是跟着方法走的,在棧內存當中。

3. 方法運行結束以後,馬上出棧,局部變量就會馬上消失。

4. 可是new出來的對象會在堆當中持續存在,直到垃圾回收消失。

 1 public class MyOuter {
 2 
 3     public void methodOuter() {
 4         int num = 10; // 所在方法的局部變量
 5 
 6         class MyInner {
 7             public void methodInner() {
 8                 System.out.println(num);// num的值不在更改就能夠訪問
 9             }
10         }
11     }
12 }
View Code

匿名內部類

若是接口的實現類(或者是父類的子類)只須要使用惟一的一次,

那麼這種狀況下就能夠省略掉該類的定義,而改成使用【匿名內部類】。

語法:

1 接口名稱 對象名 = new 接口名稱() {
2     // 覆蓋重寫全部抽象方法
3 };

對格式「new 接口名稱() {...}」進行解析:

1. new表明建立對象的動做

2. 接口名稱就是匿名內部類須要實現哪一個接口

3. {...}這纔是匿名內部類的內容

 1 public interface MyInterface {
 2 
 3     void method1(); // 抽象方法
 4 
 5     void method2();
 6 
 7 }
 8 
 9 
10 ----------------------------------------------
11 public class DemoMain {
12 
13     public static void main(String[] args) {
14 
15         // 使用匿名內部類,但不是匿名對象,對象名稱就叫objA
16         MyInterface objA = new MyInterface() {
17             @Override
18             public void method1() {
19                 System.out.println("匿名內部類實現了方法!111-A");
20             }
21 
22             @Override
23             public void method2() {
24                 System.out.println("匿名內部類實現了方法!222-A");
25             }
26         };
27         objA.method1();
28         objA.method2();
29         System.out.println("=================");
30     
31         // 及使用匿名內部類,又使用匿名對象
32         // 使用了匿名內部類,並且省略了對象名稱,也是匿名對象
33         new MyInterface() {
34             @Override
35             public void method1() {
36                 System.out.println("匿名內部類實現了方法!111-B");
37             }
38 
39             @Override
40             public void method2() {
41                 System.out.println("匿名內部類實現了方法!222-B");
42             }
43         }.method1();
44         // 由於匿名對象沒法調用第二次方法,因此須要再建立一個匿名內部類的匿名對象
45         new MyInterface() {
46             @Override
47             public void method1() {
48                 System.out.println("匿名內部類實現了方法!111-B");
49             }
50 
51             @Override
52             public void method2() {
53                 System.out.println("匿名內部類實現了方法!222-B");
54             }
55         }.method2();
56     }
57 
58 }
代碼示例

匿名內部類和匿名對象的區別:

1. 匿名內部類,在【建立對象】的時候,只能使用惟一一次

若是但願屢次建立對象,並且類的內容同樣的話,那麼就須要使用單獨定義的實現類了。

2. 匿名對象,在【調用方法】的時候,只能調用惟一一次

若是但願同一個對象,調用屢次方法,那麼必須給對象起個名字。

3. 匿名內部類是省略了【實現類/子類名稱】,可是匿名對象是省略了【對象名稱】

強調:匿名內部類和匿名對象不是一回事!!!

 

 

 

 

 

 

 

 

 

 

-------------------

相關文章
相關標籤/搜索