1?內部類
1.1?內部類的概述
將類定義在另一個類的內部則成為內部類。其實就是類定義的位置發生了變化。
在一個類中,定義在類中的叫成員變量,定義在函數中的叫成員函數,那么根據類定義的位置也可以分為成員內部類和局部內部類。
備注:內部類生產的class文件為 “外部類$內部類”,為了標明該內部類是屬于具體哪個外部類的。
1.2?成員內部類的訪問方式
- 內部類可以直接訪問外部類的成員屬性。(孫悟空相當于內部類飛到牛魔王的肚子里面去)。
- 外部類需要訪問內部類的成員屬性時需要創建內部類的對象。
- 在外部類的成員函數中創建內部類的對象,通過內部類對象對象直接訪問內部類的成員。
- 在其他類中直接創建內部類的對象。
java空指針異常舉例。Outer.Inner inner = new?Outer().new Inner();
?
外部類訪問內部類的屬性
?
java獲取異常信息。編譯異常分析:外部類需要訪問內部類的屬性時,需要創建內部類的對象訪問。
?
?
有A類和B類,當A類想要直接訪問B類中的成員,而B類又需要建立A類的對象來A類中的成員。這時,就將A類定義成B類的內部類。比喻:孫悟空和鐵扇公主。孫悟空到了公主肚子中,就成了內部類(其實是持有外部類的對象引用)。
java全局異常處理??
疑問:?什么時候使用內部類呢?
當我們分析事物時,發現事物的內部還有具體的事物,這時則應該定義內部類了。
比如人體是一個類,人體有心臟,心臟的功能在直接訪問人體的其他內容。這時就將心臟定義在人體類中,作為內部類存在。
java中的空指針異常一般怎么處理、內部類的優勢:成員內部類作為外部類的成員,那么可以訪問外部類的任意成員。
?
1.3?成員內部類訪問細節
?
?
java輸出異常信息??
私有的成員內部類不能在其他類中直接創建內部類對象來訪問。
?
如果內部類中包含有靜態成員,那么java規定內部類必須聲明為靜態的訪問靜態內部類的形式:Outer.Inner in = new Outer.Inner(); ?
?
總結:成員內部類(成員屬性、成員方法)特點:?
- 私有的成員內部類
?????特點:不能在其他類中直接創建內部類對象來訪問
- 靜態的成員內部類
?????特點:如果內部類中包含有靜態成員,那么java規定內部類必須聲明為靜的
?訪問靜態內部類的形式:
?Outer.Inner in = new Outer.Inner();
疑問:?目前打印的num是20,如果想打印10的話,應該怎么做?
解答:這時候其實在show方法中已經存在了兩個this對象,一個是外部類對象,一個是內部類對象,所以要在this前面加上類名標明對應的this。
1.4?局部內部類
局部內部類概述:包含在外部類的函數中的內部類稱之為局部內部類。
訪問:可以在包含局部內部類的方法中直接創建局部內部類的對象調用局部內部類的成員。
注意:局部內部類只能訪問所在函數的fanal屬性。
?
1.5?匿名內部類
匿名內部類:就是沒有類名字的內部類。
匿名內部類作用:簡化內部類書寫。
匿名內部類的前提:必須繼承一個父類或者是實現一個接口。
匿名內部類的格式:
new 父類或者接口(){ 執行代碼….};
內部類的寫法:
class Outer{ class Inner { public void show(){ System.out.println("內部類的show方法"); } } public void print(){ new Inner().show(); } } |
匿名內部類調用show方法:
?
案例:在外部類調用show1、show2方法。內部類的實現方法/
?
使用匿名內部類實現:?
?
注意細節:
1.使用匿名內部類時,如果需要調用匿名內部類的兩個方法或者兩個方法以上。可以使用變量指向該對象。
2?異常
2.1?現實生活的病
現實生活中萬物在發展和變化會出現各種各樣不正常的現象。
1:例如:人的成長過程中會生病。
|——病
|——不可治愈(癌癥晚期)
|——可治愈
|——小病自行解決(上火,牙痛)
|——去醫院(感冒,發燒)
2.2?java異常體系圖
現實生活中的很多病況從面向對象的角度考慮也是一類事物,可以定義為類。
java中可以通過類對這一類不正常的現象進行描述,并封裝為對象。
- java的異常體系包含在java.lang這個包默認不需要導入。
- java異常體系
|——Throwable ?(實現類描述java的錯誤和異常)
|——Error (錯誤)一般不通過代碼去處理。
|——Exceprion (異常)
|——RuntimeException (運行時異常)
|——非運行時異常
常見的Error
?
? 錯誤原因:內存溢出。需要的內存已經超出了java虛擬機管理的內存范圍。
?
錯誤原因:找不到類文件。
錯誤(Error):
它指的是一個合理的應用程序不能截獲的嚴重的問題。大多數都是反常的情況。錯誤是JVM的一個故障(雖然它可以是任何系統級的服務)。所以,錯誤是很難處理的,一般的開發人員(當然不是你)是無法處理這些錯誤的。比如內存溢出.
- 異常體系圖的對應
?
?
?
2.3?Throwable類
- toString() 輸出該異常的類名。
- getMessage() 輸出異常的信息,需要通過構造方法傳入異常信息(例如病態信息)。
- 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(); // 打印棧信息 } } |
?
2.4?程序中的異常處理
- 當除數是非0,除法運算完畢,程序繼續執行。
- 當除數是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? |
疑問:? 出現異常如何處理?
2.4.1?自行處理
- try{//可能發生異常的代碼 }catch(異常類 變量名){//處理}。
- 案例除法運算的異常處理。
- 如果沒有進行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("除法運算"); } } |
?
多個異常
- 案例print方法,形參中增加數組。
- 在print方法中操作數組會發生新的異常
ArrayIndexOutOfBoundsException,NullPointerException),如何處理?
- 使用將可能發生異常的代碼放入try語句中,添加多個catch語句即可。
- 可以處理多種異常,但是同時只能處理一種異常。
- 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("函數執行完畢"); } } |
?
總結
- 程序中有多個語句可能發生異常,可以都放在try語句中。并匹配對個catch語句處理。
- 如果異常被catch匹配上,接著執行try{}catch(){} 后的語句。沒有匹配上程序停止。
- try中多個異常同時出現,只會處理第一條出現異常的一句,剩余的異常不再處理。
- 使用多態機制處理異常。
- 程序中多態語句出現不同異常,出現了多個catch語句。簡化處理(相當于急診)。
- 使用多態,使用這些異常的父類進行接收。(父類引用接收子類對象)
?
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語句之間的執行順序。
- 是進行順序執行,從上到下。
- 如果多個catch 內的異常有子父類關系。
- 子類異常在上,父類在最下。編譯通過運行沒有問題
- 父類異常在上,子類在下,編譯不通過。(因為父類可以將子類的異常處理,子類的catch處理不到)。
- 多個異常要按照子類和父類順序進行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異常具體的子類,可以處理的更具體,不要為了簡化代碼使用異常的父類。
?
疑惑:感覺異常沒有作用.
?
?
2.4.2?拋出處理
定義一個功能,進行除法運算例如(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的區別
- 相同:都是用于做異常的拋出處理的。
- 不同點:
- 使用的位置: throws 使用在函數上,throw使用在函數內
- 后面接受的內容的個數不同:
- throws 后跟的是異常類,可以跟多個,用逗號隔開。
- 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(); } ? } |
?
總結
- try語句不能單獨存在,可以和catch、finally組成 try...catch...finally、try...catch、try...finally三種結構。
- catch語句可以有一個或多個,finally語句最多一個,try、catch、finally這三個關鍵字均不能單獨使用。
- try、catch、finally三個代碼塊中變量的作用域分別獨立而不能相互訪問。如果要在三個塊中都可以訪問,則需要將變量定義到這些塊的外面。
- 多個catch塊時候,Java虛擬機會匹配其中一個異常類或其子類,就執行這個catch塊,而不會再執行別的catch塊。(子類在上,父類在下)。
- throw語句后不允許有緊跟其他語句,因為這些沒有機會執行。
- 如果一個方法調用了另外一個聲明拋出異常的方法,那么這個方法要么處理異常,要么聲明拋出。
2.4.3?自定義異常
問題:現實中會出現新的病,就需要新的描述。
分析: java的面向對象思想將程序中出現的特有問題進行封裝。
案例: ?定義功能模擬凌波登錄。(例如:lb(String ip))需要接收ip地址
- 當沒有ip地址時,需要進行異常處理。
1. 當ip地址為null是需要throw new Exception("無法獲取ip");
??????????????? 2. 但Exception是個上層父類,這里應該拋出更具體的子類。
3. 可以自定義異常
- 自定義描述沒有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("醒醒了,開始上課了。"); } } |
?
案例:模擬吃飯沒帶錢的問題
- 定義吃飯功能,需要錢。(例如:eat(double money))
- 如果錢不夠是不能吃放,有異常。
- 自定義NoMoneyException();繼承Exception 提供有參無參構造,調用父類有參構造初始化。at 方法進行判斷,小于10塊,throw NoMoneyException("錢不夠");
- eat 方法進行聲明,throws NoMoneyException
- 如果錢不夠老板要處理。調用者進行處理。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("吃桂林米粉"); } } |
?
2.5?運行時異常和非運行時異常
2.5.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); } } |
?
2.5.2?非運行時異常(受檢異常)
如果出現了非運行時異常必須進行處理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:子類不能比父類拋出更多的異常
2.6?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{} ? |