內部類、異常 java初學-面向對象四

  1. 內部類
    1. 內部類的概述

將類定義在另一個類的內部則成爲內部類。其實就是類定義的位置發生了變化。

在一個類中,定義在類中的叫成員變量,定義在函數中的叫成員函數,那麼根據類定義的位置也可以分爲成員內部類局部內部類

備註:內部類生產的class文件爲 “外部類$內部類”,爲了標明該內部類是屬於具體哪個外部類的。

    1. 成員內部類的訪問方式
  1. 內部類可以直接訪問外部類的成員屬性。(孫悟空相當於內部類飛到牛魔王的肚子裏面去)。
  2. 外部類需要訪問內部類的成員屬性時需要創建內部類的對象。
        1. 在外部類的成員函數中創建內部類的對象,通過內部類對象對象直接訪問內部類的成員。
        2. 在其他類中直接創建內部類的對象。

Outer.Inner inner = new Outer().new Inner();

 

外部類訪問內部類的屬性

 

編譯異常分析:外部類需要訪問內部類的屬性時,需要創建內部類的對象訪問。

 

 

有A類和B類,當A類想要直接訪問B類中的成員,而B類又需要建立A類的對象來A類中的成員。這時,就將A類定義成B類的內部類。比喻:孫悟空和鐵扇公主。孫悟空到了公主肚子中,就成了內部類(其實是持有外部類的對象引用)。

 

疑問: 什麼時候使用內部類呢?

當我們分析事物時,發現事物的內部還有具體的事物,這時則應該定義內部類了。

比如人體是一個類,人體有心臟,心臟的功能在直接訪問人體的其他內容。這時就將心臟定義在人體類中,作爲內部類存在。

內部類的優勢:成員內部類作爲外部類的成員,那麼可以訪問外部類的任意成員。

 

    1. 成員內部類訪問細節

 

 

 

私有的成員內部類不能在其他類中直接創建內部類對象來訪問。

 

如果內部類中包含有靜態成員,那麼java規定內部類必須聲明爲靜態的訪問靜態內部類的形式:Outer.Inner in = new Outer.Inner();  

 

總結:成員內部類(成員屬性、成員方法)特點: 

  1. 私有的成員內部類

     特點:不能在其他類中直接創建內部類對象來訪問

  1.  靜態的成員內部類

     特點:如果內部類中包含有靜態成員,那麼java規定內部類必須聲明爲靜的

 訪問靜態內部類的形式:

 Outer.Inner in = new Outer.Inner();

疑問: 目前打印的num是20,如果想打印10的話,應該怎麼做?

解答:這時候其實在show方法中已經存在了兩個this對象,一個是外部類對象,一個是內部類對象,所以要在this前面加上類名標明對應的this。

    1. 局部內部類

局部內部類概述:包含在外部類的函數中的內部類稱之爲局部內部類。

訪問:可以在包含局部內部類的方法中直接創建局部內部類的對象調用局部內部類的成員。

注意:局部內部類只能訪問所在函數的fanal屬性。

 

    1. 匿名內部類

匿名內部類:就是沒有類名字的內部類。

匿名內部類作用:簡化內部類書寫。

匿名內部類的前提:必須繼承一個父類或者是實現一個接口。

匿名內部類的格式:

new 父類或者接口(){ 執行代碼….};

內部類的寫法:

class Outer{

class Inner

{

public void show(){

System.out.println("內部類的show方法");

}

}

public void print(){

new Inner().show();

}

}

匿名內部類調用show方法:

 

案例:在外部類調用show1、show2方法。內部類的實現方法/

 

使用匿名內部類實現: 

 

注意細節:

1.使用匿名內部類時,如果需要調用匿名內部類的兩個方法或者兩個方法以上。可以使用變量指向該對象。

  1. 異常
    1. 現實生活的病

現實生活中萬物在發展和變化會出現各種各樣不正常的現象。

1:例如:人的成長過程中會生病。

|——病

|——不可治癒(癌症晚期)

|——可治癒

|——小病自行解決(上火,牙痛)

|——去醫院(感冒,發燒)

    1. java異常體系圖

現實生活中的很多病況從面向對象的角度考慮也是一類事物,可以定義爲類。

java中可以通過類對這一類不正常的現象進行描述,並封裝爲對象。

  1. java的異常體系包含在java.lang這個包默認不需要導入。
  2. java異常體系

|——Throwable  (實現類描述java的錯誤和異常)

|——Error (錯誤)一般不通過代碼去處理。

|——Exceprion (異常)

|——RuntimeException (運行時異常)

|——非運行時異常

常見的Error

 

  錯誤原因:內存溢出。需要的內存已經超出了java虛擬機管理的內存範圍。

 

錯誤原因:找不到類文件。

錯誤(Error):

它指的是一個合理的應用程序不能截獲的嚴重的問題。大多數都是反常的情況。錯誤是JVM的一個故障(雖然它可以是任何系統級的服務)。所以,錯誤是很難處理的,一般的開發人員(當然不是你)是無法處理這些錯誤的。比如內存溢出.

  1. 異常體系圖的對應

 

 

 

    1. Throwable類
  1. toString() 輸出該異常的類名。
  2. getMessage() 輸出異常的信息,需要通過構造方法傳入異常信息(例如病態信息)。
  3. printStackTrace() 打印棧信息。

人生病:流鼻涕,感冒,呼吸道感染,肺炎。。。最後體現的是肺炎。

醫生要處理需要獲知這些信息。從外到裏處理。最後找病源

/*

 Throwable

 

 printStackTrace() 打印棧信息

 

 肺炎

 上呼吸道感染

 發燒

 流鼻涕感冒

 小感冒

 */

class Demo6 {

 

public static void main(String[] args) {

 

// Throwable able=new Throwable();

Throwable able = new Throwable("想吐。。。");

System.out.println(able.toString()); // 輸出該異常的類名

System.out.println(able.getMessage()); // 輸出異常的信息

able.printStackTrace(); // 打印棧信息

}

}

 

    1. 程序中的異常處理
  1. 當除數是非0,除法運算完畢,程序繼續執行。
  2. 當除數是0,程序發生異常,並且除法運算之後的代碼停止運行。因爲程序發生異常需要進行處理。

class Demo7 {

 

public static void main(String[] args) {

div(2, 0);

System.out.println("over");

}

 

public static void div(int x, int y) {

        //該行代碼的y值可能是0,程序會出現異常並停止

System.out.println(x / y);

System.out.println("除法運算");

}

}

//ArithmeticException 

疑問:  出現異常如何處理?

      1. 自行處理
  1. try{//可能發生異常的代碼 }catch(異常類 變量名){//處理}。
  2. 案例除法運算的異常處理。
  3. 如果沒有進行try catch處理,出現異常程序就停止。進行處理後,程序會繼續執行。

 

class Demo7 {

 

public static void main(String[] args) {

div(2, 0);

System.out.println("over");

}

 

public static void div(int x, int y) {

 

try {

System.out.println(x / y); // 可能出現異常的語句,放入try中。

} catch (ArithmeticException e) { // 進行異常匹配,

             //異常信息

System.out.println(e.toString());

    System.out.println(e.getMessage());

 e.printStackTrace();

System.out.println("除數不能爲0");

}

System.out.println("除法運算");

}

}

 

多個異常

  1. 案例print方法,形參中增加數組。
  2. 在print方法中操作數組會發生新的異常

ArrayIndexOutOfBoundsException,NullPointerException),如何處理?

        1. 使用將可能發生異常的代碼放入try語句中,添加多個catch語句即可。
        2. 可以處理多種異常,但是同時只能處理一種異常。
        3. try中除0異常和數組角標越界同時出現,只會處理一種。

public class Demo8 {

 

public static void main(String[] args) {

 

System.out.println();

int[] arr = { 1, 2 };

arr = null;

 

// print (1, 0, arr);

print (1, 2, arr);

 

System.out.println("over");

}

 

public static void print(int x, int y, int[] arr) {

 

try {

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

System.out.println(x / y);

} catch (ArithmeticException e) {

e.toString();

e.getMessage();

e.printStackTrace();

System.out.println("算術異常。。。");

} catch (ArrayIndexOutOfBoundsException e) {

e.toString();

e.getMessage();

e.printStackTrace();

System.out.println("數組角標越界。。。");

} catch (NullPointerException e) {

e.toString();

e.getMessage();

e.printStackTrace();

System.out.println("空指針異常。。。");

}

System.out.println("函數執行完畢");

}

}

 

總結

  1. 程序中有多個語句可能發生異常,可以都放在try語句中。並匹配對個catch語句處理。
  2. 如果異常被catch匹配上,接着執行try{}catch(){} 後的語句。沒有匹配上程序停止。
  3. try中多個異常同時出現,只會處理第一條出現異常的一句,剩餘的異常不再處理。
  4. 使用多態機制處理異常。
        1. 程序中多態語句出現不同異常,出現了多個catch語句。簡化處理(相當於急診)。
        2. 使用多態,使用這些異常的父類進行接收。(父類引用接收子類對象)

 

public static void div(int x, int y, int[] arr, Father f) {

 

try {

System.out.println(arr[1]); // 數組越界

System.out.println(x / y); // 除零

Son s = (Son) f; // 類型轉換

 

} catch (Exception e) {

e.toString();

e.getMessage();

e.printStackTrace();

System.out.println("出錯啦");

}

System.out.println("函數執行完畢");

}

 

多個catch語句之間的執行順序。

        1. 是進行順序執行,從上到下。
        2. 如果多個catch 內的異常有子父類關係。
              1. 子類異常在上,父類在最下。編譯通過運行沒有問題
              2. 父類異常在上,子類在下,編譯不通過。(因爲父類可以將子類的異常處理,子類的catch處理不到)。
              3. 多個異常要按照子類和父類順序進行catch

class Father {

 

}

 

class Son extends Father {

 

}

 

public class Demo8 {

 

public static void main(String[] args) {

 

System.out.println();

int[] arr = { 1, 2 };

arr = null;

Father f = new Father();

div(1, 0, arr, f);

 

System.out.println("over");

}

 

public static void div(int x, int y, int[] arr, Father f) {

 

try {

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

System.out.println(x / y);

Son s = (Son) f;

 

} catch (ArithmeticException e) {

e.toString();

e.getMessage();

e.printStackTrace();

System.out.println("算術異常。。。");

} catch (ArrayIndexOutOfBoundsException e) {

e.toString();

e.getMessage();

e.printStackTrace();

System.out.println("數組角標越界。。。");

} catch (NullPointerException e) {

e.toString();

e.getMessage();

e.printStackTrace();

System.out.println("空指針異常。。。");

} catch (Exception e) {

e.toString();

e.getMessage();

e.printStackTrace();

System.out.println("出錯啦");

}

System.out.println("函數執行完畢");

}

}

 

總結

處理異常應該catch異常具體的子類,可以處理的更具體,不要爲了簡化代碼使用異常的父類。

 

疑惑:感覺異常沒有作用.

 

 

      1. 拋出處理

定義一個功能,進行除法運算例如(div(int x,int y))如果除數爲0,進行處理。

功能內部不想處理,或者處理不了。就拋出使用throw new Exception("除數不能爲0"); 進行拋出。拋出後需要在函數上進行聲明,告知調用函數者,我有異常,你需要處理如果函數上不進行throws 聲明,編譯會報錯。例如:未報告的異常 java.lang.Exception;必須對其進行捕捉或聲明以便拋出throw  new Exception("除數不能爲0");

public static void div(int x, int y) throws Exception { // 聲明異常,通知方法調用者。

 

if (y == 0) {

throw new Exception("除數爲0"); // throw關鍵字後面接受的是具體的異常的對象

}

System.out.println(x / y);

System.out.println("除法運算");

}

 

5:main方法中調用除法功能

調用到了一個可能會出現異常的函數,需要進行處理。

1:如果調用者沒有處理會編譯失敗。

如何處理聲明瞭異常的函數。

1:try{}catch(){}

 

public static void main(String[] args) {

 

try {

div(2, 0);

} catch (Exception e) {

e.printStackTrace();

}

System.out.println("over");

 

}

 

public static void div(int x, int y) throws Exception { // 聲明異常,通知方法調用者。

 

if (y == 0) {

throw new Exception("除數爲0"); // throw關鍵字後面接受的是具體的異常的對象

}

System.out.println(x / y);

System.out.println("除法運算");

}

}

 

2:繼續拋出throws

class Demo9 {

 

public static void main(String[] args) throws Exception {

div(2, 0);

System.out.println("over");

}

 

public static void div(int x, int y) throws Exception { // 聲明異常,通知方法調用者。

if (y == 0) {

throw new Exception("除數爲0"); // throw關鍵字後面接受的是具體的異常的對象

}

 

System.out.println(x / y);

System.out.println("除法運算");

}

}

 

throw和throws的區別

  1. 相同:都是用於做異常的拋出處理的。
  2. 不同點:
  1. 使用的位置: throws 使用在函數上,throw使用在函數內
  2. 後面接受的內容的個數不同:
        1. throws 後跟的是異常類,可以跟多個,用逗號隔開。
        2. throw 後跟異常對象。

//throws 處理

public static void main(String[] args) throws InterruptedException {

Object obj = new Object();

obj.wait();

 

}

 

 

public static void main(String[] args) {

 

//try catch 處理

Object obj = new Object();

try {

obj.wait();

} catch (InterruptedException e) {

 

e.printStackTrace();

}

 

}

 

總結

        1. try語句不能單獨存在,可以和catch、finally組成 try...catch...finally、try...catch、try...finally三種結構。
        2. catch語句可以有一個或多個,finally語句最多一個,try、catch、finally這三個關鍵字均不能單獨使用。
        3. try、catch、finally三個代碼塊中變量的作用域分別獨立而不能相互訪問。如果要在三個塊中都可以訪問,則需要將變量定義到這些塊的外面。
        4. 多個catch塊時候,Java虛擬機會匹配其中一個異常類或其子類,就執行這個catch塊,而不會再執行別的catch塊。(子類在上,父類在下)。
        5. throw語句後不允許有緊跟其他語句,因爲這些沒有機會執行。
        6. 如果一個方法調用了另外一個聲明拋出異常的方法,那麼這個方法要麼處理異常,要麼聲明拋出。
      1. 自定義異常

問題:現實中會出現新的病,就需要新的描述。

分析: java的面向對象思想將程序中出現的特有問題進行封裝。

案例:  定義功能模擬凌波登錄。(例如:lb(String ip))需要接收ip地址

  1. 當沒有ip地址時,需要進行異常處理。

1. 當ip地址爲null是需要throw new Exception("無法獲取ip");

                2. 但Exception是個上層父類,這裏應該拋出更具體的子類。

3. 可以自定義異常

  1. 自定義描述沒有IP地址的異常(NoIpException)。

1. 和sun的異常體系產生關係。繼承Exception類,自定義異常類名也要規範,結尾加上Exception,便於閱讀

/*

 自定義異常

 */

class NoIpException extends Exception {

 

NoIpException() {

 

}

 

NoIpException(String message) {

super(message);

}

 

}

 

class Demo10 {

 

public static void main(String[] args) throws NoIpException {

 

System.out.println();

String ip = "192.168.10.252";

ip = null;

try {

Lb(ip);

} catch (NoIpException e) {

System.out.println("程序結束");

}

 

}

 

/*

 *

 * 凌波教學

 */

public static void Lb(String ip) throws NoIpException {

if (ip == null) {

// throw new Exception("沒插網線吧,小白");

throw new NoIpException("沒插網線吧,小白");

}

 

System.out.println("醒醒了,開始上課了。");

}

}

 

案例:模擬吃飯沒帶錢的問題

  1. 定義吃飯功能,需要錢。(例如:eat(double money))
  2. 如果錢不夠是不能吃放,有異常。
  3. 自定義NoMoneyException();繼承Exception 提供有參無參構造,調用父類有參構造初始化。at 方法進行判斷,小於10塊,throw NoMoneyException("錢不夠");
  4. eat 方法進行聲明,throws NoMoneyException
  5. 如果錢不夠老闆要處理。調用者進行處理。try{}catch(){} 。

class NoMoneyException extends Exception {

 

NoMoneyException() {

 

}

 

NoMoneyException(String message) {

super(message);

}

}

 

class Demo11 {

 

public static void main(String[] args) {

 

System.out.println();

try {

eat(0);

} catch (NoMoneyException e) {

System.out.println("跟我幹活吧。");

}

}

 

 

public static void eat(double money) throws NoMoneyException {

if (money < 10) {

throw new NoMoneyException("錢不夠");

}

System.out.println("吃桂林米粉");

}

}

 

    1. 運行時異常和非運行時異常
      1. RuntimeException

RunntimeException的子類: 

ClassCastException

多態中,可以使用Instanceof 判斷,進行規避

ArithmeticException

進行if判斷,如果除數爲0,進行return

NullPointerException

進行if判斷,是否爲null

ArrayIndexOutOfBoundsException

使用數組length屬性,避免越界

這些異常時可以通過程序員的良好編程習慣進行避免的

1:遇到運行時異常無需進行處理,直接找到出現問題的代碼,進行規避。

2:就像人上火一樣牙疼一樣,找到原因,自行解決即可

3:該種異常編譯器不會檢查程序員是否處理該異常

4:如果是運行時異常,那麼沒有必要在函數上進行聲明。

6:案例

1:除法運算功能(div(int x,int y))

2:if判斷如果除數爲0,throw new ArithmeticException();

3:函數聲明throws ArithmeticException

4:main方法調用div,不進行處理

5:編譯通過,運行正常

6:如果除數爲0,報異常,程序停止。

7:如果是運行時異常,那麼沒有必要在函數上進行聲明。

1:Object類中的wait()方法,內部throw了2個異常 IllegalMonitorStateException InterruptedException

1:只聲明瞭一個(throws) IllegalMonitorStateException是運行是異常沒有聲明。

class Demo12 {

 

public static void main(String[] args){

div(2, 1);

}

 

public static void div(int x, int y) {

if (y == 0) {

throw new ArithmeticException();  

}

System.out.println(x / y);

}

}

 

      1. 非運行時異常(受檢異常)

如果出現了非運行時異常必須進行處理throw或者try{}catch(){}處理,否則編譯器報錯。

1;IOException  使用要導入包import java.io.IOException;

2:ClassNotFoundException

2;例如人食物中毒,必須進行處理,要去醫院進行處理。

3:案例

1:定義一測試方法拋出並聲明ClassNotFoundException(test())

2:main方法調用test

3:編譯報錯

1:未報告的異常 java.lang.ClassNotFoundException;必須對其進行捕捉或聲明以便拋出

public void isFile(String path){

try

{

/*

根據文件的路徑生成一個文件對象,如果根據該路徑找不到相應的文件,

則沒法生成文件對象。

*/

File file = new File(path);

//讀取文件的輸入流

FileInputStream input = new FileInputStream(file);

//讀取文件

input.read();

}

catch (NullPointerException e)

{

System.out.println("讀取默認的文件路徑..");

}

 

}

 

4:Sun 的API文檔中的函數上聲明異常,那麼該異常是非運行是異常,

調用者必須處理。

5:自定義異常一般情況下聲明爲非運行時異常

2:函數的重寫和異常

1:運行時異常

1:案例定義Father類,定義功能拋出運行是異常,例如(test() throw

ClassCastException)

2:定義Son類,繼承Father類,定義test方法,沒有聲明異常

3:使用多態創建子類對象,調用test方法

4:執行子類方法

1:函數發生了重寫,因爲是運行時異常,在父類的test方法中,可以聲明throws 也可以不聲明throws

class Father {

void test() throws ClassCastException { // 運行時異常

System.out.println("父類");

throw new ClassCastException();

}

}

 

class Son extends Father {

void test() {

System.out.println("子類");

}

}

class Demo14 {

 

public static void main(String[] args) {

Father f = new Son();

f.test();

}

}

 

 

2:非運行時異常

1:定義父類的test2方法,拋出非運行時異常,例如拋出ClassNotFoundException

1:此時父類test2方法必須聲明異常,因爲是非運行時異常

2:Son類定義test2 方法,拋出和父類一樣的異常,聲明異常

3:使用多態創建子類對象,調用test方法,調用test2方法,

1:聲明非運行時異常的方法,在調用時需要處理,所以在main方法調用時throws

2:實現了重寫,執行子類的test2方法

3:總結子類重寫父類方法可以拋出和父類一樣的異常,或

者不拋出異常。

//  1 子類覆蓋父類方法父類方法拋出異常,子類的覆蓋方法可以不拋出異常

class Father {

void test() throws ClassNotFoundException { // 非運行時異常

System.out.println("父類");

throw new ClassNotFoundException();

}

}

 

class Son extends Father {

void test() {

System.out.println("子類");

// 父類方法有異常,子類沒有。

}

}

class Demo14 {

 

public static void main(String[] args) throws ClassNotFoundException  {

Father f = new Son();

f.test();

 

}

}

 

 

4:子類拋出並聲明比父類大的異常例如子類test2方法拋出Exception

1:編譯失敗,無法覆蓋

2:子類不能拋出父類異常的父類。

3:總結子類不能拋出比父類的異常更大的異常。

//2:子類覆蓋父類方法不比父類拋出更大異常

class Father {

void test() throws Exception {

// 非運行時異常

System.out.println("父類");

throw new Exception();

}

}

 

class Son extends Father {

void test() throws ClassNotFoundException { // 非運行時異常

System.out.println("子類");

throw new ClassNotFoundException();

}

}

class Demo14 {

 

public static void main(String[] args) throws Exception {

Father f = new Son();

f.test();

 

}

}

 

3:總結

1:子類覆蓋父類方法是,父類方法拋出異常,子類的覆蓋方法可以不拋

出異常,或者拋出父類方法的異常,或者該父類方法異常的子類。

2:父類方法拋出了多個異常,子類覆蓋方法時,只能拋出父類異常的子

3:父類沒有拋出異常子類不可拋出異常

1:子類發生非運行時異常,需要進行try{}catch的(){}處理,不能

拋出。

4:子類不能比父類拋出更多的異常

    1. finally

1: 實現方式一:

try{ // 可能發生異常的代碼 } catch( 異常類的類型 e ){ // 當發生指定異常的時候的處理代碼 }catch...

  比較適合用於專門的處理異常的代碼,不適合釋放資源的代碼。

2:實現方式二:

  try{  } catch(){} finally{ // 釋放資源的代碼 }

  finally塊是程序在正常情況下或異常情況下都會運行的。

    比較適合用於既要處理異常又有資源釋放的代碼

3:實現方式三

try{  }finally{ // 釋放資源 }

  比較適合處理的都是運行時異常且有資源釋放的代碼。

  4:finally:關鍵字主要用於釋放系統資源。

      1:在處理異常的時候該語句塊只能有一個。

  2:無論程序正常還是異常,都執行finally。

5:finally是否永遠都執行?

     1:只有一種情況,但是如果JVM退出了System.exit(0),finally就不執行。

2:return都不能停止finally的執行過程。

6:案例使用流

1:使用FileInputStream加載文件。

導包import java.io.FileInputStream;

2:FileNotFoundException  

導入包import java.io.FileNotFoundException;

3:IOException

import java.io.IOException;

public class FinallyDemo {

// 本例子使用finally 關閉系統資源。

public static void main(String[] args) {

 

FileInputStream fin = null;

try {

System.out.println("1創建io流可能出現異常");

fin = new FileInputStream("aabc.txt"); // 加載硬盤的文本文件到內存,通過流

// System.out.println(fin);

} catch (FileNotFoundException e) {

System.out.println("2沒有找到abc.txt 文件");

System.out.println("3catch 了");

// System.exit(0);

// return;

}

// finally

finally {

System.out.println("4fianlly執行");

if (fin != null) { // 如果流對象爲null 流對象就不存在,沒有必要關閉資源

try {

fin.close();

} catch (IOException e) {

e.printStackTrace();

System.out.println("close 異常");

}

 

}

System.out.println("5finally over");

}

System.out.println("6mainover");

}

}

 

// 2:無論程序正常還是異常,都執行finally。 但是遇到System.exit(0); jvm退出。

// finally用於必須執行的代碼, try{} catch(){}finally{}

// try{}finally{}

 

其他:

 面向對象 java初學   https://blog.csdn.net/fei8888888/article/details/84451429

static關鍵字 封裝、繼承和多態 java初學-面向對象二 https://blog.csdn.net/fei8888888/article/details/84537367

抽象類、多實現、多繼承 java初學-面向對象三 https://blog.csdn.net/fei8888888/article/details/84537551

包機制、訪問修飾符、Jar包 java初學 面向對象五 https://blog.csdn.net/fei8888888/article/details/84579699

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