將類定義在另外一個類的內部則成爲內部類。其實就是類定義的位置發生了變化。java
在一個類中,定義在類中的叫成員變量,定義在函數中的叫成員函數,那麼根據類定義的位置也能夠分爲成員內部類和局部內部類。程序員
備註:內部類生產的class文件爲 「外部類$內部類」,爲了標明該內部類是屬於具體哪一個外部類的。編程
Outer.Inner inner = new Outer().new Inner();數組
外部類訪問內部類的屬性jvm
編譯異常分析:外部類須要訪問內部類的屬性時,須要建立內部類的對象訪問。函數
有A類和B類,當A類想要直接訪問B類中的成員,而B類又須要創建A類的對象來A類中的成員。這時,就將A類定義成B類的內部類。比喻:孫悟空和鐵扇公主。孫悟空到了公主肚子中,就成了內部類(實際上是持有外部類的對象引用)。測試
疑問: 何時使用內部類呢?this
當咱們分析事物時,發現事物的內部還有具體的事物,這時則應該定義內部類了。spa
好比人體是一個類,人體有心臟,心臟的功能在直接訪問人體的其餘內容。這時就將心臟定義在人體類中,做爲內部類存在。指針
內部類的優點:成員內部類做爲外部類的成員,那麼能夠訪問外部類的任意成員。
私有的成員內部類不能在其餘類中直接建立內部類對象來訪問。
若是內部類中包含有靜態成員,那麼java規定內部類必須聲明爲靜態的訪問靜態內部類的形式:Outer.Inner in = new Outer.Inner();
總結:成員內部類(成員屬性、成員方法)特色:
特色:不能在其餘類中直接建立內部類對象來訪問
特色:若是內部類中包含有靜態成員,那麼java規定內部類必須聲明爲靜的
訪問靜態內部類的形式:
Outer.Inner in = new Outer.Inner();
疑問: 目前打印的num是20,若是想打印10的話,應該怎麼作?
解答:這時候其實在show方法中已經存在了兩個this對象,一個是外部類對象,一個是內部類對象,因此要在this前面加上類名標明對應的this。
局部內部類概述:包含在外部類的函數中的內部類稱之爲局部內部類。
訪問:能夠在包含局部內部類的方法中直接建立局部內部類的對象調用局部內部類的成員。
注意:局部內部類只能訪問所在函數的fanal屬性。
匿名內部類:就是沒有類名字的內部類。
匿名內部類做用:簡化內部類書寫。
匿名內部類的前提:必須繼承一個父類或者是實現一個接口。
匿名內部類的格式:
new 父類或者接口(){ 執行代碼….};
內部類的寫法:
class Outer{ class Inner { public void show(){ System.out.println("內部類的show方法"); } } public void print(){ new Inner().show(); } } |
匿名內部類調用show方法:
案例:在外部類調用show1、show2方法。內部類的實現方法/
使用匿名內部類實現:
注意細節:
1.使用匿名內部類時,若是須要調用匿名內部類的兩個方法或者兩個方法以上。可使用變量指向該對象。
現實生活中萬物在發展和變化會出現各類各樣不正常的現象。
1:例如:人的成長過程當中會生病。
|——病
|——不可治癒(癌症晚期)
|——可治癒
|——小病自行解決(上火,牙痛)
|——去醫院(感冒,發燒)
現實生活中的不少病況從面向對象的角度考慮也是一類事物,能夠定義爲類。
java中能夠經過類對這一類不正常的現象進行描述,並封裝爲對象。
|——Throwable (實現類描述java的錯誤和異常)
|——Error (錯誤)通常不經過代碼去處理。
|——Exceprion (異常)
|——RuntimeException (運行時異常)
|——非運行時異常
常見的Error
錯誤緣由:內存溢出。須要的內存已經超出了java虛擬機管理的內存範圍。
錯誤緣由:找不到類文件。
錯誤(Error):
它指的是一個合理的應用程序不能截獲的嚴重的問題。大多數都是反常的狀況。錯誤是JVM的一個故障(雖然它能夠是任何系統級的服務)。因此,錯誤是很難處理的,通常的開發人員(固然不是你)是沒法處理這些錯誤的。好比內存溢出.
人生病:流鼻涕,感冒,呼吸道感染,肺炎。。。最後體現的是肺炎。
醫生要處理須要獲知這些信息。從外到裏處理。最後找病源
/* 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(); // 打印棧信息 } } |
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 |
疑問: 出現異常如何處理?
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("除法運算"); } } |
多個異常
ArrayIndexOutOfBoundsException,NullPointerException),如何處理?
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("函數執行完畢"); } } |
總結
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語句之間的執行順序。
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異常具體的子類,能夠處理的更具體,不要爲了簡化代碼使用異常的父類。
疑惑:感受異常沒有做用.
定義一個功能,進行除法運算例如(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 處理 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(); }
} |
總結
問題:現實中會出現新的病,就須要新的描述。
分析: java的面向對象思想將程序中出現的特有問題進行封裝。
案例: 定義功能模擬凌波登陸。(例如:lb(String ip))須要接收ip地址
1. 當ip地址爲null是須要throw new Exception("沒法獲取ip");
2. 但Exception是個上層父類,這裏應該拋出更具體的子類。
3. 能夠自定義異常
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("醒醒了,開始上課了。"); } } |
案例:模擬吃飯沒帶錢的問題
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("吃桂林米粉"); } } |
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); } } |
若是出現了非運行時異常必須進行處理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: 實現方式一:
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{} |