Java基礎語法09-面向對象下-內部類

九、內部類

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

(1)成員內部類:聲明在外部類中方法外

  • 靜態成員內部類

  • 非靜態成員內部類

(2)局部內部類:聲明在外部類的方法體中

  • 有名字的局部內部類

  • 匿名的內部類

靜態內部類

1、語法格式:

【修飾符】 class 外部類 【extends 父類】 【implements 接口們】{
  【其他修飾符】 static class 靜態內部類 【extends 父類】 【implements 接口們】{
   }
}

外部類的權限修飾符:public或缺省,其他修飾符:abstract或final

靜態內部類的權限修飾符:四種,其他修飾符:abstract或final + static

2、靜態內部類也是類

(1)可以有自己的父類或父接口

(2)有自己的字節碼文件:外部類名$靜態內部類名.class

(3)有自己的成員:沒有限制

只要在類中可以寫的成員它都可以有,只有靜態內部類允許有靜態成員。

3、靜態內部類的使用

(1)靜態內部類使用外部類的成員時:

有限制:靜態內部類不能使用外部類的非靜態成員

(2)在外部類中使用靜態內部類

使用靜態內部類的靜態成員:直接使用“靜態內部類名."

使用靜態內部類的非靜態成員:使用“靜態內部類的對象."

(3)在外部類的外面使用靜態內部類

前提:這個靜態內部類在外面是可見,否則只能通過這個靜態內部類的父類或父接口來引用它的對象。

如果可見,使用靜態內部類的靜態成員:直接使用“外部類名.靜態內部類名."

使用靜態內部類的非靜態成員:使用“靜態內部類的對象."

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

非靜態內部類

1、語法結構:

【修飾符】 class 外部類 【extends 父類】 【implements 接口們】{
  【其他修飾符】 class 非靜態內部類 【extends 父類】 【implements 接口們】{
   }
}

外部類的權限修飾符:public或缺省,其他修飾符:abstract或final

非靜態內部類的權限修飾符:四種,其他修飾符:abstract或final

2、非靜態內部類也是類

(1)可以有自己的父類或父接口

(2)有自己的字節碼文件:外部類名$非靜態內部類名.class

(3)有自己的成員:有限制

不能有靜態成員,除非靜態常量。

3、非靜態內部類的使用

(1)非靜態內部類使用外部類的成員時:沒有限制

(2)在外部類中使用非靜態內部類

在外部類的靜態成員中使用無法使用非靜態內部類的。

在外部類的非靜態成員中使用非靜態內部類,使用“非靜態內部類的對象."

在非靜態內部類的方法中有兩個this對象,一個是外部類的this對象,一個是內部類的this對象

(3)在外部類的外面使用非靜態內部類

前提:這個非靜態內部類在外面是可見,否則只能通過這個非靜態內部類的父類或父接口來引用它的對象。

如果可見,使用非靜態內部類的非靜態成員:要求必須有外部類的對象的引用

外部類 out = new 外部類(【...】);
外部類.非靜態內部類 對象名 = out.new 非靜態內部類(【...】);

//在實際開發中,在外部類中編寫一個方法來返回非靜態內部類的對象,然後調用這個方法來獲取非靜態內部類對象

局部內部類

【修飾符】 class 外部類 【extends 父類】 【implements 接口們】{
  【修飾符】 返回值類型 方法名(【形參列表】){
    【abstract或final或沒有】 class 局部內部類 【extends 父類】 【implements 接口們】{
     }
   }
}

外部類的權限修飾符:public或缺省,其他修飾符:abstract或final

局部內部類沒有權限修飾符,其他修飾符:abstract或final

局部內部類的特點:

  • 和外部類一樣,它只是定義在外部類的某個方法中的另一個完整的類結構

    • 可以繼承自己的想要繼承的父類,實現自己想要實現的父接口們,和外部類的父類和父接口無關

    • 可以在局部內部類中聲明屬性、方法、構造器等結構,但不包括靜態成員,除非是從父類繼承的或靜態常量

    • 可以使用abstract修飾,因此它也可以被同一個方法的在它後面的其他內部類繼承

    • 可以使用final修飾,表示不能被繼承

    • 編譯後有自己的獨立的字節碼文件,只不過在內部類名前面冠以外部類名、$符號、編號。

      • 這裏有編號是因爲同一個外部類中,不同的方法中存在相同名稱的局部內部類

  • 和成員內部類不同的是,它前面不能有權限修飾符等

  • 局部內部類如同局部變量一樣,有作用域

  • 局部內部類中是否能訪問外部類的靜態還是非靜態的成員,取決於所在的方法

  • 局部內部類中還可以使用所在方法的局部常量,即用final聲明的局部變量

    • JDK1.8之後,如果某個局部變量在局部內部類中被使用了,自動加final

在外部類中使用局部內部類

有作用域,即只能在這個方法體中,並且在聲明之後。

在外部類的外面使用局部內部類:不能

在外部類的外面可以得到局部內部類的對象

但是需要通過它的父類或父接口的變量來引用,用方法的返回值返回。

匿名內部類

匿名內部類是沒有名字的類,因此在聲明類的同時就創建好了唯一的對象。

匿名內部類的對象一般會三種形式使用它

父類/父接口 變量 = new 父類/父接口(【實參列表】){
  //可以寫方法....
};

new 父類/父接口(【實參列表】){
  //可以寫方法....
}.方法(【實參列表】);

方法名(new 父類/父接口(【實參列表】){
  //可以寫方法....
});

所有局部內部類的限制都適用於匿名內部類。例如:

  • 在匿名內部類中是否可以使用外部類的非靜態成員變量,看所在方法是否靜態

  • 在匿名內部類中如果需要訪問當前方法的局部變量,該局部變量需要加final

思考:這個對象能做什麼呢?

答:(1)調用某個方法(2)賦值給父類/父接口的變量,通過多態引用使用這個對象(3)作爲某個方法調用的實參

註解

和普通註釋不同:註解的註釋內容是可以被另一段程序讀取的

一個完整的註解應該有三個部分:

(1)聲明: @interface

(2)使用: @註解名 或 @註解名(....)

(3)讀取:

  • SOURCE:只能由編譯器讀取

  • CLASS:可以由類加載器讀取

  • RUNTIME:可以通過反射的代碼在運行時讀取

系統預定義的三個最基本的註解

1、@Override

用於檢測被修飾的方法爲有效的重寫方法,如果不是,則報編譯錯誤!

只能標記在方法上。

2、@Deprecated

用於表示被標記的數據已經過時,不建議使用。

可以用於修飾 屬性、方法、構造、類、包、局部變量、參數。

3、@SuppressWarnings

抑制編譯警告。

可以用於修飾類、屬性、方法、構造、局部變量、參數

格式:

@SuppressWarnings("all")
@SuppressWarnings("uncheck")
@SuppressWarnings({"unused","uncheck"})

文檔註釋

  • @author 標明開發該類模塊的作者,多個作者之間使用,分割

  • @version 標明該類模塊的版本

  • @see 參考轉向,也就是相關主題

  • @since 從哪個版本開始增加的

  • @param 對方法中某參數的說明,如果沒有參數就不能寫

  • @return 對方法返回值的說明,如果方法的返回值類型是void就不能寫

  • @throws/@exception 對方法可能拋出的異常進行說明 ,如果方法沒有用throws顯式拋出的異常就不能寫

    • 其中 @param @return 和 @exception 這三個標記都是隻用於方法的。

    • @param的格式要求:@param 形參名 形參類型 形參說明

    • @return 的格式要求:@return 返回值類型 返回值說明

    • @exception 的格式要求:@exception 異常類型 異常說明

    • @param和@exception可以並列多個

javadoc.exe就是這些註解的信息處理流程。

如果導出時有亂碼問題,可以指定字符編碼

-docencoding UTF-8
-encoding UTF-8
-charset UTF-8

JUnit單元測試

  • @Test:標記在非靜態的測試方法上。
  • @BeforeClass:標記在靜態方法上。因爲這個方法只執行一次。在所有方法@Test方法之前執行。

  • @AfterClass:標記在靜態方法上。因爲這個方法只執行一次。在所有方法@Test方法完成後執行。

  • @Before:標記在非靜態方法上。在@Test方法前面執行,而且是在每一個@Test方法前面都執行

  • @After:標記在非靜態方法上。在@Test方法後面執行,而且是在每一個@Test方法後面都執行

  • @BeforeClass、@AfterClass、@Before、@After都是配合@Test使用的,單獨使用沒有意義。

元註解

(1)@Target:用於描述註解的使用範圍

  • 可以通過枚舉類型ElementType的10個常量對象來指定

(2)@Retention:用於描述註解的生命週期

  • 可以通過枚舉類型RetentionPolicy的3個常量對象來指定

  • 唯有RUNTIME階段才能被反射讀取到。

(3)@Documented:表明這個註解應該被 javadoc工具記錄。

(4)@Inherited:允許子類繼承父類中的註解

自定義註解

@元註解
【修飾符】 @interface 註解名{
  數據類型 參數名1();
  數據類型 參數名2() default 默認值;
}

(1)聲明時,類型有要求:

8種基本數據類型、String、枚舉、Class、註解,以及他們的數組

(2)使用時

可以在定義 Annotation 的成員變量時爲其指定初始值, 指定成員變量的初始值可使用 default 關鍵字

如果定義的註解含有配置參數,那麼使用時必須指定參數值,除非它有默認值。格式是“參數名 = 參數值”,如果只有一個參數成員需要賦值,且名稱爲value,可以省略“value=”

自定義註解必須配上註解的信息處理流程纔有意義。

異常

對於異常,一般有兩種解決方法:一是遇到錯誤就終止程序的運行。另一種方法是由程序員在編寫程序時,就考慮到錯誤的檢測、錯誤消息的提示,以及錯誤的處理。

異常的根類是java.lang.Throwable,其下有兩個子類:java.lang.Errorjava.lang.Exception,平常所說的異常指java.lang.Exception

如果要自定義異常,必須繼承Throwable或它的子類

Error:嚴重錯誤Error,無法通過處理的錯誤,只能事先避免

Exception:表示異常,其它因編程錯誤或偶然的外在因素導致的一般性問題,程序員可以通過代碼的方式糾正,使程序繼續運行,是必須要處理的。

Exception的兩大類:編譯時異常和運行時異常

運行時異常:RuntimeException或它的子類

編譯時異常:除了運行時異常都是編譯時異常

Java異常處理的五個關鍵字:try、catch、finally、throw、throws

1、try:嘗試執行可能會發生異常的代碼

2、catch:嘗試捕獲try中發生的異常

3、finally:無論try中是否發生異常,也無論catch是否可以捕獲異常,也不管try和catch中是否有return語句,都要執行。除非在try或catch中執行了System.exit(0)語句。

4、throw:用於手動拋出異常

5、throws:表示某個方法內部沒有處理xx異常,拋給調用者處理,在方法的簽名中顯式聲明拋出哪些異常

try{
  可能發生異常的代碼
}catch(異常類型 e){
  處理異常的代碼
  //打印,或什麼都不寫,或者其他處理代碼
}catch(異常類型 e){
  處理異常的代碼
  //打印,或什麼都不寫,或者其他處理代碼
}finally{
  ...
}

throw用在方法內,用來拋出一個異常對象,將這個異常對象傳遞到調用者處,並結束當前方法的執行。

throw new 異常類名(參數);

關鍵字throws運用於方法聲明之上,用於表示當前方法不處理異常,而是提醒該方法的調用者來處理異常(拋出異常).

修飾符 返回值類型 方法名(參數) throws 異常類名1,異常類名2…{   }

在方法中使用try-catch的語句塊來處理異常。

try:該代碼塊中編寫可能產生異常的代碼。

catch:用來進行某種異常的捕獲,實現對捕獲到的異常進行處理。

  • 可以有多個catch塊,按順序匹配。

  • 如果多個異常類型有包含關係,那麼小上大下

finally:有一些特定的代碼無論異常是否發生,都需要執行。另外,因爲異常會引發程序跳轉,導致有些語句執行不到。而finally就是解決這個問題的,在finally代碼塊中存放的代碼都是一定會被執行的。

 

注意:finally不能單獨使用。當只有在try或者catch中調用退出JVM的相關方法,例如System.exit(0),此時finally纔不會執行,否則finally永遠會執行。

一般我們是使用一次捕獲多次處理方式

注意:這種異常處理方式,要求多個catch中的異常不能相同,並且若catch中的多個異常之間有子父類異常的關係,那麼子類異常要求在上面的catch處理,父類異常在下面的catch處理。

  • 運行時異常被拋出可以不處理。即不捕獲也不聲明拋出。

  • 如果finally有return語句,永遠返回finally中的結果,避免該情況.

  • 如果父類拋出了多個異常,子類重寫父類方法時,拋出和父類相同的異常或者是父類異常的子類或者不拋出異常。

  • 父類方法沒有拋出異常,子類重寫父類該方法時也不可拋出異常。此時子類方法中產生了編譯時異常,只能捕獲處理,不能聲明拋出

自定義異常

要求

1、必須繼承Throwable或它的子類,一般繼承Exception或RuntimeException

2、儘量保留兩個構造器:無參和有參(message)

3、加序列化版本ID

4、自定義異常類型的對象只能使用throw語句拋出

自定義異常最重要的是異常類的名字,當異常出現時,可以根據名字判斷異常類型。

 常見異常列表

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章