java程式設計–孫鑫java無難事Lesson4《內部類、異常處理》

來源:互聯網
上載者:User
java程式設計--孫鑫java無難事Lesson4《內部類、異常處理》

1.內部類的特性和使用方法
概念總述:
在一個類中定義另外一個類,這個類就叫做內部類或內建類 (inner class) 。
內部類可以讓我們將邏輯上相關的一組類組織起來,並由外部類(outer class)來控制內部類的可見度。
當我們建立一個inner class時,其對象就擁有了與外部類對象之間的一種關係,這是通過一個特殊的this reference形成的,使得內部類對象可以隨意的訪問外部類中所有的成員。

詳細內容:

(1)外部類的main靜態方法中無法直接存取內部類,錯誤資訊如下:

//*********************************************************************************

Outer.java:30: 錯誤: 無法從靜態上下文中引用非靜態 變數 this
        Inner inner=new Inner();
(2)引用內部類時需要一個外部類的執行個體來引用

否則錯誤資訊如下:

//*********************************************************************************

Outer.Inner inner=new Outer.Inner();
        inner.print();//error
Outer.java:46: 錯誤: 需要包含Outer.Inner的封閉執行個體
                Outer.Inner inner=new Outer.Inner();
(3)內部類訪問外部類的成員、中介層類的成員、和本地變數

測試代碼及結果如下:

//*********************************************************************************

class  Outer  //外部類
{   
    private int index=100;//外部類成員
    //內部類Inner類不管嵌套層次多深,都可以訪問外部類成員
    void fn( final int a)
    {   
        //ok 類的範圍限定在if語句中 仍然可以訪問外部類成員
        final int b=0;//需要初始化
        if(true)
        {   
            class Middle    //中間類
            {
                           private int index=70;////中間類成員
                class Inner   //內部類
                {   
                    private int index=50;//內部類成員
                    void print()
                    {   
                       int index=30;
                       System.out.println(index);//30
                       System.out.println(this.index);//50
                       System.out.println(Middle.this.index);//70
                       System.out.println(Outer.this.index);//100
                       System.out.println(a);//ok 聲明為final時
                       System.out.println(b);//ok 聲明為final時
                    }
                }
            }
        }
}

(4)在方法中定義的內部類,如果要存取方法中定義的本地變數或方法的參數,則變數必須被聲明final,否則出錯,錯誤資訊如下:

//*********************************************************************************

Outer.java:38: 錯誤: 從內部類中訪問本地變數a; 需要被聲明為最終類型a=5;
Outer.java:39: 錯誤: 從內部類中訪問本地變數b; 需要被聲明為最終類型b=6;                
(5)private內部類  

內部類聲明為private時無法訪問,否則錯誤資訊如下:

//*********************************************************************************

Outer.java:133: 錯誤: Outer.Inner可以在Outer中訪問private Outer.Inner inner=outer.new Inner();
內部類還可以聲明為protected、abstract或final。
(6)static內部類  

內部類可以聲明為static的,但此時就不能再使用外部類的非static的成員變數和非static的成員方法,否則錯誤資訊如下:

//*********************************************************************************

Outer.java:102: 錯誤: 無法從靜態上下文中引用非靜態 變數 this
                   System.out.println(Outer.this.index);//error  
(7)非static的內部類中的成員不能聲明為static的,只有在頂層類或static的內部類中才可聲明static成員,

否則錯誤資訊如下:

//*********************************************************************************

Outer.java:110: 錯誤: 內部類Outer.Inner中的靜態聲明非法
                static void print()
修飾符 'static' 僅允許在常量變數聲明中使用
(8)內部類繼承

內部類無法直接繼承,類定義如下:

//*********************************************************************************

class Car
{   
    class Wheel{}
}
class PlaneWheel extends Car.Wheel
{
    public static void main(String[] args) {
            PlaneWheel pw=new PlaneWheel();
        System.out.println("Hello World!");
    }
}
則錯誤資訊如下:
Car.java:9: 錯誤: 需要包含Car.Wheel的封閉執行個體
class PlaneWheel extends Car.Wheel
解決方案:
class Car
{   
    class Wheel{}
}
class PlaneWheel extends Car.Wheel
{       
        //產生外部類對象
        PlaneWheel(Car car)
    {
        car.super();
    }
    public static void main(String[] args)
    {   
        Car car=new Car();
        PlaneWheel pw=new PlaneWheel(car);
    }
}
(9)匿名內部類

匿名內部類測試代碼1如下:

//*********************************************************************************

interface Animal
{
    void eat();
    void sleep();
}
class  Zoom
{   
    //隱藏實現細節  通過介面訪問內部類的方法
    private class Tiger implements  Animal
    {
        public void eat()
        {
            System.out.println("Tiger eat");
        }
        public void sleep()
        {
            System.out.println("Tiger sleep!");
        }
    }
     Animal getanimal()
    {  
      //介面無法直接執行個體化對象  需要使用匿名內部類 實現介面中的方法
      return new Animal()
      {
          public void eat()
        {
            System.out.println("Animal eat");
        }
        public void sleep()
        {
            System.out.println("Animal sleep!");
        }
      };
    }
}
class Test
{
    public static void main(String[] args)
    {   
        Zoom zoom=new Zoom();
        Animal an=zoom.getanimal();
        an.eat();
        an.sleep();
    }

}

//*********************************************************************************

//輸出結果
Animal eat

Animal sleep!

//*********************************************************************************

匿名內部類測試代碼2如下:

//*********************************************************************************

class A
{   
    void fn1(){}
}
abstract class B
{
    abstract void fn2();
}
class C extends A
{   
    //使用匿名內建類 返回內建類對象
    B getB()
    {
       return new B()
       {
          public void fn2(){};//實現抽象類別B的方法
       };
    }
}
class Test
{
    static void method1(A a)
    {
        a.fn1();
    }
    static void method2(B b)
    {
        b.fn2();
    }
    public static void main(String[] args)
    {   
        C c=new C();
        method1(c);
        method2(c.getB());
    }
}
(10)利用內部類解決方案重名問題

測試代碼如下:

//*********************************************************************************

interface Machine
{
    void run();
}
class Person
{
    public void run()
    {
        System.out.println("run");
    }
}
//需要繼承 但是繼承的同時方法與介面中方法重名 利用內部類解決
class Robot extends Person
{
    private class MachineHeart implements Machine
    {
        public void run()
        {
           System.out.println("heart run");
        }
    }
    Machine getmachine()
    {
       return new MachineHeart();
    }
}
class Test
{
    public static void main(String[] args)
    {   
        Robot robot =new Robot();
        Machine m=robot.getmachine();
        m.run();
        robot.run();
    }

}

//*********************************************************************************

//輸出結果
heart run
run
2.異常處理
概念總述:
Java程式在執行過程中如出現異常,會自動產生一個異常類對象,該異常對象將被提交給Java運行時系統,這個過程稱為拋出(throw)異常。
當Java運行時系統接收到異常對象時,會尋找能處理這一異常的代碼並把當前異常對象交給其處理,這一過程稱為捕獲(catch)異常。
如果Java運行時系統找不到可以捕獲異常的方法,則運行時系統將終止,相應的Java程式也將退出。

詳細內容:

(1)構造一個除0異常,捕獲異常資訊如下:

//*********************************************************************************

Exception in thread "main" java.lang.ArithmeticException: / by zero
        at Excep.division(Excep.java:5)
        at ExcepTest.main(Excep.java:14)
(2)捕獲異常的位置--try catch語句塊
try語句中發生異常後的語句將不予執行,但是catch語句後的語句予以執行。異常處理代碼放置在catch語句中。

(3)拋出異常而沒有捕獲異常時,錯誤資訊如下:

//*********************************************************************************

Excep.java:53: 錯誤: 未報告的異常錯誤Exception; 必須對其進行捕獲或聲明以便拋出
                System.out.println( excep.division(5,0));
(4)捕獲異常順序--特殊到一般

已經捕獲了Exception,再次捕獲ArithmeticException時錯誤資訊如下:

//*********************************************************************************

Excep.java:51: 錯誤: 已捕獲到異常錯誤ArithmeticException
                catch( ArithmeticException e)
(5)RuntimeException運行時異常並不需要顯示的捕獲
對於RuntimeException,通常不需要我們去捕獲,這類異常由Java運行系統自動拋出並自動處理。

(6)捕獲異常後可以繼續拋出異常

//*********************************************************************************

public int division(int a ,int b) throws ArithmeticException

{   
    //在函數內部捕獲異常
    try
    {
        return a/b;
    }
    catch (ArithmeticException e)
    {    
             e.printStackTrace();//輸出異常資訊
         throw e;//再次拋出異常 程式跳轉
    }
}

//捕獲異常資訊如下:

//*********************************************************************************

java.lang.ArithmeticException: / by zero
        at Excep.division(Excep.java:33)
        at ExcepTest.main(Excep.java:75)
Exception in thread "main" java.lang.ArithmeticException: / by zero
        at Excep.division(Excep.java:33)
        at ExcepTest.main(Excep.java:75)

(7)捕獲異常後可以重新拋出新的異常

//*********************************************************************************

public int division(int a ,int b) throws Exception
{   
    //在函數內部捕獲異常
    try
    {
        return a/b;
    }
    catch (ArithmeticException e)
    {    
            e.printStackTrace();//輸出異常資訊後
        throw new Exception("can not div zero!");//再次拋出新異常
    }

}

//*********************************************************************************

捕獲異常資訊如下:

F:\java\JavaLesson\Lesson4>java ExcepTest
java.lang.ArithmeticException: / by zero
        at Excep.division(Excep.java:33)
        at Excep.fn1(Excep.java:45)
        at ExcepTest.main(Excep.java:58)
java.lang.Exception: can not div zero!
        at Excep.division(Excep.java:38)
        at Excep.fn1(Excep.java:45)
        at ExcepTest.main(Excep.java:58)
(8)自訂異常

從Exception派生子類如下:

//*********************************************************************************

class  DivisorIsMinusException extends Exception
{
    DivisorIsMinusException(String str)
    {
        super(str);
    }
}
自訂異常類的使用如下:
public int division(int a ,int b) throws ArithmeticException ,DivisorIsMinusException
    {   
        if(b<0)
                throw new DivisorIsMinusException("Divisor can't be minus!");
        return a/b;
    }
    int fn1(int a,int b)   throws ArithmeticException ,DivisorIsMinusException
    {
        return division(a,b);

    }

//*********************************************************************************

//異常捕獲資訊如下:
F:\java\JavaLesson\Lesson4>java ExcepTest
DivisorIsMinusException: Divisor can't be minus!
        at Excep.division(Excep.java:52)
        at Excep.fn1(Excep.java:57)
        at ExcepTest.main(Excep.java:77)
(9)finally執行機會
不管異常發生沒有,finally均會執行,適合在此處做一些清理和資源釋放工作
finally語句執行不受return語句限制,但是使用exit退出時不會執行.

在Test.java中執行如下測試代碼:

//*********************************************************************************

try
    {   
        System.out.println( excep.fn1(5,-2));
        return;//finally語句仍會執行
    }
    catch( ArithmeticException e)
    {
       System.out.println( e.toString() );
    }
    //捕獲自訂異常
    catch (DivisorIsMinusException ex)
    {
        ex.printStackTrace();
        System.exit(-1);//finally語句不會執行
    }
    //捕獲一般異常
    catch (Exception e)
    {
        e.printStackTrace();//列印異常資訊和位置
    }
    finally
    {
       System.out.println( "finally!");

    }

//*********************************************************************************

//運行結果
F:\java\JavaLesson\Lesson4>java ExcepTest
DivisorIsMinusException: Divisor can't be minus!
        at Excep.division(Excep.java:52)
        at Excep.fn1(Excep.java:57)
        at ExcepTest.main(Excep.java:77)
finally!
(10)子類覆蓋父類的方法中拋出異常時受限制
如果父類中的方法拋出多個異常,則子類中的覆蓋方法要麼拋出相同的異常,要麼拋出異常的子類,但不能拋出新的異常(註:構造方法除外)。
以下測試代碼,子類試圖覆蓋父類方法的同時拋出新的異常.
//*****************************************************
class Excep
{
    public int division(int a ,int b) throws Exception  
    {   
        try
        {
            return a/b;
        }
        catch (ArithmeticException e)
        {    
                    e.printStackTrace();//輸出異常資訊後
        }
    }
}
class ChildExcep extends Excep
{   
       //error    子類覆蓋父類方法時拋出異常受限制
    public int division(int a ,int b) throws FileNotFoundException
    {   
        return a/b;
    }

}

//*********************************************************************************

以上代碼編譯會出錯,錯誤資訊如下:
Excep.java:63: 錯誤: ChildExcep中的division(int,int)無法覆蓋Excep中的division(in
t,int) public int division(int a ,int b) throws FileNotFoundException
被覆蓋的方法未拋出FileNotFoundException
(11)我們可以在方法聲明時,聲明一個不會拋出的異常,Java編譯器就會強迫方法的使用者對異常進行處理。這種方式通常應用於abstract base class和interface中。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.