1. 程式人生 > >Java基礎之內部類、匿名類和異常處理知識點總結

Java基礎之內部類、匿名類和異常處理知識點總結

     Object是java中已有的一個所有類的父類。也稱為根類,你可以把它理解為java中的上帝。java中的類都是直接或者間接繼承自object類。
該類的出現:是封裝了所有物件都具備的方法。所有物件都具備方法有哪些呢?
     boolean  equals(Object obj):對物件進行比較。該方法的預設是比較記憶體地址,所以很多物件都對該方法進行復寫。建立物件的自己比較是否相同的方式。     StringtoString():將物件變成字串:格式: 物件型別@物件雜湊值,但是這個結果沒什麼意義,所以,該方法一般也會被覆蓋,建立該物件的自己特有的對應字串的表現形式。     inthashCode():獲取每一個物件的雜湊值,可以理解為是地址值,是通過雜湊演算法完成的。
ClassgetClass():獲取一個物件的所屬位元組碼檔案物件。 void finalize():垃圾回收器呼叫的垃圾回收方法。釋放資源和釋放記憶體。
例子1:Object類具備的方法例項演示。
package cn.itheima.day15;
class Demo {
    /**
     * Demo類本身是Object類的子類,具備了物件的比較相同的功能:equals(),因為是繼承
     * 過來的,而equals()方法是對地址值進行比較的,所以沒什麼意義。
     * 所以想要建立Demo類自己的獨特的比較方式。
     * 既然父類中已經有了比較的功能,所以,子類只要繼承該功能,並複寫該功能即可。
     */
	private int num;
	public Demo(int num) {
		this.num = num;
	}
	/**
	 * 建立Demo類的物件的比較方式,只要覆蓋equals()方法介面。
	 * 沿襲父類的功能宣告即可,定義子類的功能具體的實現。
	 * 一般情況下,描述物件,都會對該方法複寫,建立該物件特有的比較是否相同的功能。
	 */
	//複寫equals()方法
	public boolean equals(Object obj){
		if(this==obj)  //提高效率
			return true;
		if(!(obj instanceof Demo))   //增加健壯性
			return false;
		Demo d = (Demo)obj; //向下轉型,是為了使用子類的特有功能。
		if(this.num == d.num){
			return true;
		}
		return false;
	}
	//複寫toString()方法
	public String toString(){
		return "Demo's num="+num;
	}
}
class Person{
}
public class ObjectDemo {
	public static void main(String[] args) {
		Demo d1 = new Demo(5);
		Demo d2 = new Demo(7);
		Demo d3 = new Demo(5);
		System.out.println(d1);
		System.out.println(d2);
		System.out.println(d3);
		System.out.println(d1.hashCode());
		//任何一個物件都需要載入其對應的位元組碼檔案來完成。
		//也就說任何一個物件都有自己對應的位元組碼檔案。
                //如何獲取該位元組碼檔案呢?
		//是通過Object 類中的getClass方法來完成。
		Class clazz = d1.getClass();
		//getClass方法返回的是d1這個物件所對應的位元組碼檔案物件。Demo.class檔案物件。
		System.out.println(clazz.getName());

		Person p = new Person();
		System.out.println(p.getClass().getName());
		System.out.println(d1.equals(d2));
		System.out.println(d1.equals(d3));
		//通過列印結論:equals()方法其實實在對物件的地址值進行判斷
		//判斷兩個物件是否是同一個地址。
		/*Demo d1 = new Demo(5);
		Demo d2 = new Demo(7);
		Demo d3 = new Demo(5);
		boolean b = d1.equals(d2);
		boolean b1 = d1.equals(d3);
		System.out.println("b="+b);
		System.out.println("b1="+b1);
		System.out.println(d1==d2);
		System.out.println(d1==d3);*/
	}
}
例子2:垃圾回收器finalize()方法的例項演示。
package cn.itheima.day15;
class Demo1{
	public void finalize(){   //至少做了兩件事:釋放關聯底層資源,釋放記憶體空間
		System.out.println("finalize run");
	}
}
/**
 * 被垃圾回收器是在不定時的時間啟動。
 * 現在準備手動呼叫垃圾回收器。
 * @author wl-pc
*/
public class FinalizeDemo {
	public static void main(String[] args) throws InterruptedException {
		new Demo1();
		new Demo1();
		new Demo1();
		Thread.sleep(10);
        System.gc();  //啟動垃圾回收器
	}
}
內部類:又叫內建類或者巢狀類。將類定義在另一個類中,該類就是內部類。類中定義的類就是內部類。其實類的定義位置發生了一點小變化。
訪問方式     內部類可以直接訪問外部類中的成員。
     外部類想要訪問內部類,需要建立內部類物件。
例子1:定義一個內部類的應用例項。
package cn.itheima.day15;
class Outer{
    private int num = 3;
    class Inner{  //定義的內部類
    	void show(){
    		System.out.println("inner show run--"+num);
    	}
    }
    public void method(){
    	Inner in = new Inner();
    	in.show();
    }
}
public class InnerClassDemo {
	public static void main(String[] args) {
		Outer out = new Outer();
		out.method();
	}
}
/**
 *  class Body{
		private class Heart{	
		}
		public Heart getHeart(){
			if(...); //具有可控制性
			return new Heart();
		}
     }
	class Main{	
        Body body = new Body();
        Body.getHeart();
	}
 */
有A類和B類,當A類想要直接訪問B類中的成員,而B類又需要建立A類的物件,來訪問A類中的成員。這時,就將A類定義成B類的內部類。比喻:孫悟空和鐵扇公主。孫悟空到了公主肚子中,就成了內部類。
class B{
   class A{}
}
什麼時候定義內部類呢?
當分析一個事物時,該事物的內部還有具體的事物,這個具體的事物在使用該事物中的其他成員。這時就將這個具體的事物用內部類來描述。
比如:人體是一個類,人體有心臟,心臟的功能在直接訪問人體的其他內容。這時就將心臟定義在人體類中,作為內部類存在。
而且內部類通常都不會直接對外提供,都會封裝到外部類中,外部了一般會通過對外提供方法的形式對其進行訪問內部類只有預設許可權修飾符,或者 public修飾符時,可以被外部類直接訪問到。
    Outer.Innerin = new Outer().new Inner();
注意要保證的是該內部類必須定義在外部類的成員位置上。
格式:外部類名.內部類名 變數 = 外部類物件.內部類物件;
但是一般不會這麼用,因為內部類都會被外部類隱藏,通常都是外部類提供方法獲取內部類的物件。這樣可以對獲取物件可控。通常內部類都會被private私有化。
    Outer.Inner in = new Outer().new Inner();
    in.show();
當內部類中如果有靜態成員時,該內部類也必須是靜態的。而靜態內部類只能訪問外部類中的靜態成員。    
在執行static內部類方法時,兩種情況。
    1,內部類靜態,但是方法沒靜態。該方法需要被物件呼叫執行。
          Outer.Inner in = new Outer.Inner();//產生了一個靜態內部類物件。
          in.show();
    2,內部類靜態,而且方法也是靜態的。靜態內部類隨著物件的載入就已經存在了,靜態方法隨著內部類的載入也存在了。這時是不需要物件的。
         Outer.Inner.show();
例子2:內部類中的靜態和非靜態的方法以及變數訪問方式。
package cn.itheima.day15;
class Outer2{
	private int num = 4;
	static int num2 = 8;  //只要內部類定義在成員位置上,就可以被成員修飾符所修飾。
	static class Inner{   //靜態內部類只能訪問外部類中的靜態成員。
		static void show(){
			System.out.println("show run::"+num2);
		}
	}
	/*public void method(){
		Inner in = new Inner();
		in.show();
	}*/
}
public class InnerClassDemo2 {
	public static void main(String[] args) {
		/*Outer2 out = new Outer2();
		out.method();*/
		/*Outer2.Inner out= new Outer2().new Inner();
		out.show();*/
		//Outer2.Inner in = new Outer2.Inner(); //產生了一個靜態內部類物件。
		//in.show();
		Outer2.Inner.show();
	}
}
非靜態的內部類之所以可以直接訪問外部類中的成員,那是因為內部類中都持有一個外部類物件引用:外部類名.this
靜態的內部類之所以可以直接訪問外部類中的靜態成員,其實持有的是外部類名。記住只有內部類定義在成員位置上,才可以有這些成員修飾符。
例子3:定義在成員位置上的內部類的修飾符用法例項演示。
package cn.itheima.day15;
class Outer3{
	 int num = 4;
	 static int num2 =9;
	 class Inner{   
		int num = 8;  
		void show(){
			int num = 3;
			System.out.println("show run::"+num);   //列印3
			System.out.println("show run::"+this.num);   //列印8(用this是呼叫內部類自身的成員變數)
			System.out.println("show run::"+Outer3.this.num);  //列印4(用類名.this是在呼叫外部類中的成員變數)
		}
	}
	 static class Inner2{
		 static void function(){
			 System.out.println("show run::"+num2);  //列印9 這時省略了Outer3.num2
		 }
	 }
	 public static void method2(){
		 Inner2 in2 = new Inner2();
		 in2.function();
	 }
	public void method(){
		Inner in = new Inner();
		in.show();
	}
}
public class InnerClassDemo3 {
	public static void main(String[] args) {
		Outer3 out = new Outer3();
		//out.method();
		out.method2();
	}
}
內部類定義在類中的區域性位置。內部類定義區域性位置上,只能訪問該區域性中的被final修飾的常量。
例子4:內部類定義在類中的區域性位置上。
package cn.itheima.day15;
/**
 * 內部類定義在類中的區域性位置上。
 * 內部類定義區域性位置上,只能訪問該區域性中的被final修飾的常量。
 * @author wl-pc
*/
class Outer4{
	 int num = 4;
	 public void method(){
		 final int num2 = 8;  //定義常量
		 class Inner{   
			 void show(){
				 System.out.println("show run::"+num2);  
			 }	
		 }
		 new Inner().show();
	 }
}
public class InnerClassDemo4 {
	public static void main(String[] args) {
		new Outer4().method();
	}
}
匿名內部類:就沒有名字的內部類。
    好處:簡化了內部類的書寫。
    前提:內部類必須要繼承或者實現一個外部類或外部介面
匿名內部類的格式:
    new 父類名或者介面(){
         裡面定義該父類或者介面的子類成員。
    }
匿名內部類其實就是一個子類匿名物件。這是一個帶有內容的物件,這個物件有點胖。
例子5:匿名內部類的例項演示。
package cn.itheima.day15;
/**
 * 匿名內部類
 * @author wl-pc
 */
abstract class AbsDemo{
	abstract void show();
}
class Outer5{
	private int num = 4;
/*	class Inner extends AbsDemo{
		void show(){
			System.out.println("num="+num);
		}
	}*/
	//匿名內部類的格式
	public void method(){
		new AbsDemo() {   //匿名內部類其實就是一個子類匿名物件
			@Override
			void show() {
				System.out.println("num==="+num);
			}
		}.show();
	}
}
public class NiMingInnerDemo {
	public static void main(String[] args) {
		new Outer5().method();
	}
}
例子6:匿名物件的面試題。
package cn.itheima.day15;
//定義一個介面
interface Inter{
	void show1();
	void show2();
}
class Outer6{
    /*class Inner implements Inter{
		@Override
		public void show1() {
			System.out.println("show1 run");	
		}
		@Override
		public void show2() {
			System.out.println("show2 run");
		}*/
		public void method(){
			Inter in = new Inter(){
				public void show1(){
					System.out.println("show1 run");
				}
				public void show2(){
					System.out.println("show2 run");
				}
			};
			in.show1();
			in.show2();
		}
    }
class Demo2{
	void function(){
		System.out.println("demo funtion run");
	}
}
public class NiMingInnerDemo2 {
	public static void main(String[] args) {
	//new Outer6().method();
        //new Demo2().function();  //建立Demo類的物件,呼叫function方法。
        //需求:想要使用Demo類子類複寫function後的該方法。
     	new Demo2(){   //建立了一個Demo類的子類匿名物件
			void function(){
				System.out.println("heima");
			}
		}.function();
	}
	//面試題:
	/*new Object(){
		void method(){
			System.out.println("method run");
		}
	}.method();//問?可不可以執行? 可以的。
    */	
	//問下面的情況可不可以?
	Object obj = new Object(){
	  void method(){
		  System.out.println("method run");
	  }	
	};
	//obj.method();  //會編譯失敗
	//原因解釋:
	/**
	 * 分析:等號右邊的部分是一個Object類的子類物件,
	 * 用匿名內部類來表示的。當把這個物件賦值給Object型別
	 * 的obj時,該子類物件就是向上轉型為了Object。obj中是
	 * 沒有定義過method方法。這就是我們說在多型時,一般非靜態
	 * 函式被呼叫時,編譯看左邊(Object中有沒有method()方法呢?
	 * 沒有,則編譯失敗),執行看右邊的原理。
	 * (舉例:貓是動物,會抓老鼠,所以動物都會抓老鼠)錯誤想法。
	 */
	/*
	class Test extends Object{
		void method(){}
	}
	new Test().method();
	Object obj = new Test();
	obj.method();//編譯失敗 
	*/
}
什麼時候使用匿名內部類呢?
當函式的引數是一個介面型別的引用,而且該介面中的方法不超過3個。這時可以給這個函式傳遞一個匿名內部類實際引數進入。簡化書寫。
例子7:匿名內部類的例項演示。
package cn.itheima.day15;
interface Inter2{
   void show();	
}
class Outer7{
	//補足程式碼,要求用匿名內部類來體現。
	static Inter2 method(){
		return new Inter2(){  //返回介面的子類物件
			public void show(){
				System.out.println("show run");
			}
		};
	}
}
public class NiMingTest {
	public static void main(String[] args) {
		 //Inter in = Outer.method();
                 //in.show();
                //Outer7.method().show();// Outer7.method():說明Outer7類中有一個method方法。
                                     //這個方法時直接被Outer7所訪問,代表這個方法時靜態的。
                //Outer7.method()方法執行完,還可以呼叫show()方法,說明method執行結束後,會返回一個
                //show方法所屬介面Inter2的子類物件。而且method方法返回值型別肯定是Inter2.
		//舉例說明:當函式的引數是一個介面型別的引用,而且該介面中的方法不超過3個。
		//這時可以給這個函式傳遞一個匿名內部類實際引數進入
		function(new Inter2(){
			public void show(){
				System.out.println("inner show run");
			}
		});
	    }
public static void function(Inter2 in){  //可以給這個函式(function)傳遞一個匿名內部類實際引數進入.
			in.show();
		}
}	
異常:就是程式執行時出現的不正常情況
例子8:異常的演示程式碼。
package cn.itheima.day15;
class Demo4{
	public int div(int a,int b){
		return a/b;
	}
	public void method(){
		int[] arr = new int[3];
		System.out.println(arr[3]);
	}
}
public class ExceptionDemo {
	public static void main(String[] args) {
		Demo4 d = new Demo4();
		/*int num = d.div(4, 0);  //除0異常
		System.out.println("num="+num);
		System.out.println("over");*/
		d.method();   //角標越界異常ArrayIndexOutOfBoundsException
		System.out.println("over");
	}
}
          發現,當呼叫者往裡傳入了除數0,就發生。編譯通過(語法沒錯誤),而執行失敗的情況。出現一個ArithmeticException:/ by zero 一個異常。執行提前終止,後續的程式碼就不會在執行了。
其實異常就是程式中出現的問題:這個問題包括:問題的名稱,問題的資訊,以及問題出現的位置。這個問題中內部中的有很多,按照面向物件將這個問題封裝成了物件。
通過if判斷形式,也可以對問題進行處理。但是這樣會導致,問題處理程式碼和正常的業務流程程式碼都定義在了一起,不便於閱讀,當把問題封裝成物件後,當該問題產生後,可以讓程式進行跳轉有一個特定的區域對問題進行處理。
這樣,異常的出現可以是問題處理程式碼和業務邏輯程式碼相分離,提高了程式的閱讀性。Java對常見的一系列都進行了描述,並進行了物件的封裝。
查閱一下API。發現異常中很多子類。
因為常見問題很多,就對這些問題進行描述並建立了體系。
異常問題分為兩大類:
    1,可以處理的問題。
             一般用Exception(異常)來進行描述。這個問題可以有針對性的程式碼進行處理。
    2,重大錯誤問題,
            用Error進行描述。這個問題發生後,一般不編寫針對的程式碼進行處理,而是要對程式進行修正。
通常都有JVM丟擲的問題。
    這兩個派系,他們的子類都有一個共同特徵:所有子類名成結尾都是以父類名作為字尾。
問題:就如同疾病:可以治癒的疾病。Exception也有絕症。Error.無論錯誤還是異常,他們都有:名稱標識,同時也有問題的資訊、問題出現的位置。
既然有這樣的共性可以向上繼續抽取。它們都有了一個共同的父類Throwable,該父類中就定義了該體系中最共性的方法.
      String getMessage():獲取異常的資訊。
      String toString():將異常物件變成字串。其實該類是覆蓋Object類中的toString();
      void printStackTrace():列印異常在記憶體中的詳細資訊。直接列印到控制檯。
異常的處理。有兩種       1,將異常丟擲。
       2,使用java中指定的程式碼塊進行自定義處理。
           try{
               需要檢測異常的程式碼;
           }
           catch(異常類 變數){
               異常處理程式碼;
          }
         finally{
              一定會被執行的程式碼;
         }
例子9:異常處理的例項演示。
package cn.itheima.day15;
class Demo5{
	public int div(int a,int b){
		return a/b;
	}
}
public class ExceptionDemo2 {
	public static void main(String[] args) {
		Demo5 d = new Demo5();
		try {
			int num = d.div(4, 0);  //除0異常
			System.out.println("num="+num);
		} catch (Exception e) {   //定義一個異常類的引用,用於接收發生的異常。
		System.out.println("有異常存在!");
		System.out.println("message:"+e.getMessage());  //只返回異常資訊
		System.out.println("toStrig:"+e.toString());//既有異常資訊,又有異常類名稱
		e.printStackTrace(); //異常名稱,異常資訊,異常出現的位置。都列印在控制檯上。
		//發現沒有進行trycatch處理時,由jvm預設處理的結果和printStackTrace的結果一致。
		//說明jvm的預設處理方式,就是在呼叫異常的printStackTrace方法。並讓程式停止。
		}
		System.out.println("over");
	}
}
處理異常:
      要麼throws(丟擲異常),要麼try…cacth。到底是try…cacth好呢?還是throws好呢?
      原則:如果該功能內部可以將問題處理,用try…cacth,如果處理不了,交由呼叫者處理,這時用throws。
例子10:try…cacth和throws(丟擲異常)例項演示。
package cn.itheima.day15;
/**
 * 呼叫了div功能,該功能並未宣告有任何問題,所以呼叫者是不需要進行鍼對處理。 
 *   但是這樣程式會有安全隱患。
 *   所以在定義div功能時,就需要將容易發生的問題,明確出來,這樣才方便於呼叫者進行處理.
 * 怎麼明確呢?
 *   可以在功能上通過throws關鍵字將問題的名稱標識出來,讓呼叫者可以知道.
 * @author wl-pc
 */
class Demo6{
	public int div(int a,int b) throws Exception{
		return a/b;
	}
}
public class ExceptionDemo3 { //throws Exception //丟擲異常(主函式就拋給了虛擬機器JVM)
	public static void main(String[] args) {
		Demo6 d = new Demo6();
		try {
			int num = d.div(4, 0);  //除0異常
			System.out.println("num="+num);
		} catch (Exception e) {
			System.out.println("發生異常!");
		}
		System.out.println("over");
	}
}
     如果使用到了一個聲明瞭異常的功能時,必須要對應的丟擲throws或者try的處理方式。否則編譯失敗。但是有一種特殊情況。當功能上宣告的異常是一個特殊的異常子類時,這時該功能被呼叫,可以不用任何處理方式,一樣可以編譯通過。這個特殊異常就是Exception中的一個子類RuntimeException。(執行時異常)
異常分兩種:
   1,編譯時被檢測的異常.包括除了Exception子類RuntimeException以外的所有異常。如果在函式上宣告,如果呼叫時,沒有處理方式,編譯會編譯。而且這種異常需要有針對性的處理方式。是可被處理的。
   2,編譯時不被檢測的異常:包括RuntimeException以及子類。
    該異常也稱為執行時異常,如果功能聲明瞭此異常,呼叫者可以不用任何處理方式。通過該異常不需宣告。如果發生,就是需要程式停止,對程式碼進行修正。
例子11:執行時異常的例項演示。
package cn.itheima.day15;
class Demo7 {
	public int div(int a,int b) throws RuntimeException{
		return a/b;
	}
}
public class ExceptionDemo4 { 
	public static void main(String[] args) {
		Demo7 d = new Demo7();
		int num = d.div(4, 0);  //除0異常
		System.out.println("num="+num);
		System.out.println("over");
	}
}
在自定義專案中,也會有很多問題發生,這些問題,有可能是專案特有問題,是沒有被java所描述的。那麼這時,就需要我們繼續按照java的異常思想,將特有問題也封裝成物件。自定義異常。將特有的問題進行描述,並封裝成物件。
//在下面示例中,要求,除數不可以為負數。
這種問題java沒有提供先有的描述方式。所以只有自己進行描述。
自定義異常的步驟:
    定義一個類對問題描述。要想成為異常,必須繼承異常類才可以。這樣才可以成為異常體系中的一員。其實最根本原因:異常體系和其他物件的不同之處在於異常體系都具備可拋性。
    異常的類和物件都可以被兩個關鍵字所操作,而且只有異常體系具備這個特點,哪兩個關鍵字呢?throws和throw
當函式內容通過throw丟擲了一個編譯時檢測的異常。必須要有處理方式。要麼try,要麼throws。
處理調用出現異常的函式的原則:
呼叫了宣告異常的函式,處理時,對方宣告什麼異常,我們就處理什麼異常。自定義異常可以繼承Exception,也可以繼承RuntimeException。如果該問題發生,不需要宣告需要是呼叫修正程式碼,那麼就需要繼承RuntimeException。
throws和throw的區別:
       throws用在函式上,用於宣告該功能容易出現問題。可以呼叫者進行處理的。
       throw用在函式內,用於丟擲指定的具體異常物件。
       throws後面跟的是異常類。可以跟多個,中間用逗號隔開。
       throw後面跟的是異常物件。
       只有異常體系的類和物件才可以被這兩個關鍵字所操作。
例子12.自定義異常類的例項演示。
package cn.itheima.day15;
class FuShuException extends RuntimeException{ //Exception{
	private int num;
	public FuShuException(String msg,int num) {
		super(msg);
		this.num = num;
	}
	public int getNum(){
		return num;
	}
}
class Demo8 {
	public int div(int a,int b) {//throws FuShuException{  
		//如果標示throws FuShuException,則主函式會去執行的,
		//而往往我們是希望出現異常,是不往下執行的,所以不要標示出
		if(b<0)
			 //手動將異常封裝成物件,並手動通過throw關鍵字將異常丟擲,引起程式跳轉
			 //因為程式發生異常後,運算是無法繼續執行的。
			throw new FuShuException("除數不能為負數", b); 
		return a/b;
	}
}
public class ExceptionDemo5 { 
	public static void main(String[] args) {
		Demo8 d = new Demo8();
		//try {
		int num = d.div(4, -1);  
		System.out.println("num="+num);
		//} catch (FuShuException e) {
			//System.out.println("負數產生!");
			//System.out.println(e.getMessage());
			//System.out.println(e.toString());
			//System.out.println("負數是:"+e.getNum());
		//}
		System.out.println("over");	
	}
}
//分析FuShuException怎樣自定義一個異常的類
/*class Throwable{
	private String message;
	public Throwable(String message) {
		this.message = message;
	}
	public String getMessage(){
		return message;
	}
}
class Exception extends Throwable{
	public Exception(String message) {
		super(message);
	}
}
class FuShuException extends Exception{
	FuShuException(String message){
		super(message);
	}
}*/
例子13.異常的處理的例項演示。
package cn.itheima.day15;
/**
 * 老師用電腦上課。
 * 在老師上課的時候容易出現的問題:
 *    1.電腦藍屏
 *    2.電腦冒煙
 * @author wl-pc
 *  分析事物是,要考慮容易出現的問題,當然我們應該儘量的避免問題的出現
 *  ,但是如果避免不了,應該預先的給出處理方式。
 *  需要將分析出來的問題進行描述,並將其封裝成物件,
 */
//電腦藍屏異常
class LanPingException extends Exception{
	public LanPingException(String msg) {
		super(msg);
	}
}
//電腦冒煙異常
class MaoYanException extends Exception{
	public MaoYanException(String msg) {
		super(msg);
	}
}
//當電腦發生問題後,會導致老師講課的進度無法繼續的問題出現
class NoPalanException extends Exception{  //講課的進度無法繼續異常
	public NoPalanException(String msg) {
		super(msg);
	}
} 
//定義電腦的例項物件
class computer{  //try異常後是不需要在宣告丟擲異常的,但是如果要不處理異常,那就得宣告丟擲的異常
	int state = 2;
	void run() throws LanPingException, MaoYanException{
		if(state == 1){
			throw new LanPingException("電腦藍屏!");
		}
		if(state == 2){
			throw new MaoYanException("電腦冒煙!");
		}
		System.out.println("電腦執行!");
	}
	void reset(){
		state = 0;
		System.out.println("電腦重啟!");
	}
}
//定義老師例項
class Teacher{
	private String name;
	private computer cmp;
	public Teacher(String name) {
		this.name = name;
		cmp = new computer();
	}
    //上課
	void preflect() throws NoPalanException {
		try {
			cmp.run();
			System.out.println(name+"開始上課!");
		} catch (LanPingException e) {
			System.out.println("藍屏!");
			cmp.reset();
			preflect();
		} catch (MaoYanException e1){
			System.out.println(e1.getMessage());
			test();
			//new dnweixiou().weixiou(cmp);
			throw new NoPalanException("課程無法繼續"+e1.getMessage()); //異常轉換:將異常封裝,暴露出呼叫可以解決的異常。
		}
	}
	void test(){
		System.out.println("大家做練習!");
	}
}
/*class dnweixiou{
	void weixiou(computer cmp){
		cmp.reset();
	}
}*/
public class ExceptionTest {
	public static void main(String[] args) throws MaoYanException {
		Teacher t = new Teacher("畢老師");
        try {
			t.preflect();
		} catch (NoPalanException e) {
			System.out.println(e.getMessage());
		}
	}
}
/*
 * 舉例說明:異常的封裝,將本層的特定的異常進行本層的處理。
 * 通過處理完對外暴露,將問題高數呼叫者,給呼叫者提供一個
 * 可以處理的異常。這就是異常轉換。
 * class SQLperate{
 *      void add() throw new SQLException{
 *           攔截資料庫。
 *           新增資料。 //這時會丟擲異常throw new SQLException
 *           關閉資料庫。 
 *        }catch(SQLException e){
 *           //解決資料庫異常的程式碼。
 *           throw new NoAddException();
 *        }   
 *      }
 * }
 * //向資料庫中沒新增成功的異常
 * class NoAddException extends Exception{
 *     ......
 * }
 * class Demo{
 *    main(){
 *        try{
 *           new SQLperate().add(); 
 *        }catch(NoAddException e){
 *           throw new NoAddException("新增資料失敗");
 *        }
 *    }
 * }
 * */
finally程式碼塊。finally程式碼塊中定義是用於關閉資源的程式碼。
舉例:
操作資料庫。無論資料是否新增成功,都需要進行資料庫的關閉動作,因為關閉動作可以釋放資料庫的資源。提高資料庫的效能。
void add(){
    try{
       連線資料庫。
       新增資料。
    }
    catch(SQLExceptione){
       異常處理方式。
    }
    finally{
       關閉資料庫
    }
}
Try…catch…finally在使用的時候,try可以和catch相結合使用,可以對應多個catch。如果沒有catch,try可以和finally結合使用。
如果功能中,出現了編譯時“需要被檢測的異常”字樣時,如果沒有被catch,就必須要throws宣告,否則編譯失敗
記住:只有catch是處理異常的程式碼塊.
void show()throws Excpetion{
    try{
       code();//使用了底層資源。
       thrownew Excpetion();
    }   
    finally{
       資源釋放。
    }
}
例子14. Finally用法的例項演示。
package cn.itheima.day15;
class Demo9{
	public int div(int a,int b) throws Exception{
		return a/b;
	}
}
public class ExceptionDemo6 { 
	public static void main(String[] args) {
		Demo9 d = new Demo9();
		try {
			int num = d.div(4, 0);  //除0異常
			System.out.println("num="+num);
		} catch (Exception e) {
			System.out.println(e.toString());
			//return;
			System.exit(0); //退出javajvm。
		}finally{  //只有一種情況finally執行不到。退出jvm。
			System.out.println("finally run");
		}
		System.out.println("over");
	}
}
異常的處理細節:
    1,當子類覆蓋父類時,如果父類的方法丟擲了異常,那麼子類覆蓋父類要麼不拋異常,要麼丟擲該異常或者該異常的子類。
    2,如果父類丟擲了多個異常,子類覆蓋父類時,只能丟擲這些異常子集。
簡單一句話:子類只能拋父類的異常或者異常的子類或子集。子類不可以丟擲父類沒有的異常

例子15.異常處理的細節例項。

package cn.itheima.day15;
/**
 * Exception
 *    |--AException
 *          |--BException
 *    |--CException
 * @author wl-pc
*/
class AException extends Exception{
}
class BException extends AException{
}
class CException extends Exception{
}
class Fu{
	void show() throws AException{
		System.out.println("Fu");
	}
}
class Tool{
	void method(Fu f){
		try {
			f.show();
		} catch (AException e) {
			e.printStackTrace();
		}
	}
}
class Zi extends Fu{
	void show() throws AException{  //還可以丟擲BException,但是不可以丟擲CException
		System.out.println("Zi");
	}
}
public class ExceptionDemo7 { 
	public static void main(String[] args) {
		Tool tool = new Tool();
		tool.method(new Zi());
	}
}
注意:如果被覆蓋的方法沒有異常丟擲,那麼子類的方法絕對不可以丟擲異常。如果子類方法內還有異常發生。那麼子類只能try,不能throws.
面試細節:當try對應多個catch時,如果catch的型別有繼承關係,那麼父型別的catch一定要放在下面.
/*
 * class Fu{
	void show()throws AException,CException,Exception{
	}
}
try {
	new Fu().show();
}
catch(AException e){
}
catch(CException e){
}
catch(Exception e){
}
 * */
 */
void method()
{
   if()
	   throw new RuntimeException();
	System.out.println("haha");//永遠執行不到。是一句標準的廢話。
}