Java 1.1通過對Java語言規范進行修改,顯著簡化了一些實用結構的實現。在那些修改中,最引人注目的就是內部類和匿名類。如運用得當,它們可使程序更易理解和維護。下面來看看這些特性具體是如何工作的,如何正確使用它們,以及如何避免一些常見的錯誤。
內部類 簡單地說,“內部類”是在另一個類的內部聲明的類。從Java 1.1開始,你可在一個類中聲明另一個類,這與聲明字段和方法非常相似。包裝了內部類聲明的類就稱為“外部類”。 實際上,Java語言規范還允許你做更多的事情,包括: 在另一個類或者一個接口中聲明一個類。 在另一個接口或者一個類中聲明一個接口。 在一個方法中聲明一個類。 類和接口聲明可嵌套任意深度。 清單A是類和接口的一些空白聲明,它演示了這些可能性。 使用一個import語句,你可像使用其他任何標准類那樣省略package名稱。此外,在外部類中,可利用簡單名稱來引用所有內部類和接口(參見清單A中的new語句)。注意從Method1中引用Inner2仍需指定Interface1,因為Inner2在一個不同的級別上。 表A總結了清單A中聲明的每個內部類和接口的完全限定名稱。用了import語句之後,就可采用較短的形式。當然,在外部類中,你還可省略外部類的名稱。 名稱 類/接口 Inner1 mypackage.Inner1 Interface1 mypackage.Interface1 Inner2 mypackage.Interface1.Inner2 Interface2 mypackage.Interface1.Interface2 Inner3 Inner3對於Method1來說是local的,所以它不可在方法外部訪問
引用內部類 內部類最自然的一種應用就是聲明只在另一個類的內部使用的類,或者聲明與另一個類密切相關的類。如清單B所示,它是一個鏈表的簡單實現。由於Node類通常只在LinkedList的范圍內使用,所以最好將Node聲明為LinkedList的一個內部類。 適用於類成員的訪問控制修改符也適用於內部類;也就是說,內部類可以具有package、protected、private和public訪問權限,它們的語義和正常的語義沒有什麼不同。由於Node要在LinkedList的外部使用,所以把它聲明為public。 然而,修飾符static具有不同的含義。應用於內部類時,它聲明的類具有與其他類相同的語義,也就是可進行實例化,並像一個標准類那樣使用。惟一的區別就是它擁有對外部類的所有靜態成員的完全訪問權限。清單C展示了一個簡單的程序,它創建一個鏈表,並將它打印到標准輸出設備。
非靜態內部類 如果內部類沒有指定static修飾符,就擁有對外部類的所有成員的完全訪問權限,包括實例字段和方法。為實現這一行為,非靜態內部類存儲著對外部類的實例的一個隱式引用。 所以,對一個非靜態內部類進行實例化需要采用不同語法的new語句: .new 這種形式的new語句要求外部類的一個實例,使內部類能在那個實例的上下文中創建。注意清單A聲明了幾個非靜態內部類,並用標准的new語句在Method1中實例化它們。之所以能那樣做,是因為Method1是外部類的一個實例方法,所以new語句會在外部類的一個實例的上下文中隱式地執行。只有在外部類的外部或者在其他對象的上下文中實例化一個非靜態內部類時,才需要使用修改過的語法。 但是,非靜態內部類具有一些限制。尤其是,它們不能聲明靜態初始化列表和靜態成員,除非是在常量字段中。此外,方法內部聲明的內部類不能訪問方法的局部變量和參數,除非它們被初始化成final。
匿名類 匿名類是不能有名稱的類,所以沒辦法引用它們。必須在創建時,作為new語句的一部分來聲明它們。 這就要采用另一種形式的new語句,如下所示: new <類或接口> <類的主體> 這種形式的new語句聲明一個新的匿名類,它對一個給定的類進行擴展,或者實現一個給定的接口。它還創建那個類的一個新實例,並把它作為語句的結果而返回。要擴展的類和要實現的接口是new語句的操作數,後跟匿名類的主體。 如果匿名類對另一個類進行擴展,它的主體可以訪問類的成員、覆蓋它的方法等等,這和其他任何標准的類都是一樣的。如果匿名類實現了一個接口,它的主體必須實現接口的方法。 注意匿名類的聲明是在編譯時進行的,實例化在運行時進行。這意味著for循環中的一個new語句會創建相同匿名類的幾個實例,而不是創建幾個不同匿名類的一個實例。 從技術上說,匿名類可被視為非靜態的內部類,所以它們具有和方法內部聲明的非靜態內部類一樣的權限和限制。 如果要執行的任務需要一個對象,但卻不值得創建全新的對象(原因可能是所需的類過於簡單,或者是由於它只在一個方法內部使用),匿名類就顯得非常有用。匿名類尤其適合在Swing應用程序中快速創建事件處理程序。 清單D就是一個非常簡單的Swing應用程序,它展示了與匿名類有關的幾個概念。這個例子創建了兩個匿名類。第一個對java.awt.event.WindowAdapter進行擴展,並在應用程序窗口關閉時調用應用程序的onClose方法。 即使onClose聲明為private,匿名類也能調用它,因為匿名類本質上是應用程序類的一個內部類。第二個匿名類實現了Java.awt.ActionListener接口,它在一個按鈕被按下後關閉應用程序窗口。注意匿名類可以訪問本地變量frame。這是由於匿名類在與frame相同的方法內部聲明。然而,frame要被聲明為final,否則會生成編譯錯誤。
更優化的代碼 內部和匿名類是Java 1.1為我們提供的兩個出色的工具。它們提供了更好的封裝,結果就是使代碼更容易理解和維護,使相關的類都能存在於同一個源代碼文件中(這要歸功於內部類),並能避免一個程序產生大量非常小的類(這要歸功於匿名類)。