Java內部類及其實例化<br />在Java 中,允許在一個類(或方法、語句塊)的內部定義另一個類,稱為內部類(Inner Class),有時也稱為嵌套類( Nested Class)。
內部類和外層封裝它的類之間存在邏輯上的所屬關係,一般只用在定義它的類或語句塊之內,實現一些沒有通用意義的功能邏輯,在外部引用它時必須給出完整的名稱。
使用內部類的主要原因有:
內部類可以訪問外部類中的數據,包括私有的數據。
內部類可以對同一個包中的其他類隱藏起來。
當想要定義一個回調函數且不想編寫大量代碼時,使用匿名(anonymous)內部類比較便捷。
減少類的命名衝突。
請看下面的例子:
public class Outer { private int size; public class Inner { private int counter = 10; public void doStuff() { size++; } } public static void main(String args[]) { Outer outer = new Outer(); Inner inner = outer.new Inner(); inner.doStuff(); System.out.println(outer.size); System.out.println(inner.counter); // 編譯錯誤,外部類不能訪問內部類的變量System. out.println(counter); }}
這段代碼定義了一個外部類Outer,它包含了一個內部類Inner。將錯誤語句註釋掉,編譯,會生成兩個.class 文件:Outer.class 和Outer$Inner.class。也就是說,內部類會被編譯成獨立的字節碼文件。
內部類是一種編譯器現象,與虛擬機無關。編譯器將會把內部類翻譯成用$ 符號分隔外部類名與內部類名的常規類文件,而虛擬機則對此一無所知。
注意:必須先有外部類的對象才能生成內部類的對象,因為內部類需要訪問外部類中的成員變量,成員變量必須實例化才有意義。
內部類是Java 1.1 的新增特性,有些程序員認為這是一個值得稱讚的進步,但是內部類的語法很複雜,嚴重破壞了良好的代碼結構, 違背了Java要比C++更加簡單的設計理念。
內部類看似增加了―些優美有趣,實屬沒必要的特性,這是不是也讓Java開始走上了許多語言飽受折磨的毀滅性道路呢?本教程並不打算就這個問題給予一個肯定的答案。
Java靜態內部類、匿名內部類、成員式內部類和局部內部類內部類可以是靜態(static)的,可以使用public、protected 和private 訪問控制符,而外部類只能使用public,或者默認。
成員式內部類
在外部類內部直接定義(不在方法內部或代碼塊內部)的類就是成員式內部類,它可以直接使用外部類的所有變量和方法,即使是private 的。外部類要想訪問內部類的成員變量和方法,則需要通過內部類的對象來獲取。
請看下面的代碼:
public class Outer{ private int size; public class Inner { public void dostuff() { size++; } } public void testTheInner() { Inner in = new Inner(); in.dostuff(); }}
成員式內部類如同外部類的一個普通成員。
成員式內部類可以使用各種修飾符,包括public、protected、private、static、final 和abstract,也可以不寫。
若有static 修飾符,就為類級,否則為對象級。類級可以通過外部類直接訪問,對象級需要先生成外部的對像後才能訪問。
非靜態內部類中不能聲明任何static 成員。
內部類可以相互調用,例如:
class A { // B、C 間可以互相調用class B {} class C {}}
成員式內部類的訪問
內部類的對像以成員變量的方式記錄其所依賴的外層類對象的引用,因而可以找到該外層類對象並訪問其成員。該成員變量是系統自動為非static 的內部類添加的,名稱約定為“outClassName.this”。
1) 使用內部類中定義的非靜態變量和方法時,要先創建外部類的對象,再由“outObjectName.new”操作符創建內部類的對象,再調用內部類的方法,如下所示:
public class Demo{ public static void main(String[] args) { Outer outer = new Outer(); Outer.Inner inner = outer.new Inner(); inner.dostuff(); }}class Outer{ private int size; class Inner{ public void dostuff() { size++; } }}
2) static 內部類相當於其外部類的static 成員,它的對象與外部類對象間不存在依賴關係,因此可直接創建。示例如下:
public class Demo{ public static void main(String[] args) { Outer.Inner inner = new Outer.Inner(); inner.dostuff(); }}class Outer{ private static int size; static class Inner { public void dostuff () { size++; System.out.println("size=" + size); } }}
運行結果:
size=1
3) 由於內部類可以直接訪問其外部類的成分,因此當內部類與其外部類中存在同名屬性或方法時,也將導致命名衝突。所以在多層調用時要指明,如下所示:
public class Outer{ private int size; public class Inner{ private int size; public void dostuff(int size){ size++; // 局部變量size; this.size; // 內部類的size Outer.this.size++; //外部類的size } }}
局部內部類
局部內部類(Local class)是定義在代碼塊中的類。它們只在定義它們的代碼塊中是可見的。
局部類有幾個重要特性:
局部類可以是abstract 的。
請看下面的代碼:
public class Outer { public static final int TOTAL_NUMBER = 5; public int id = 123; public void func() { final int age = 15; String str = "http://www.weixueyuan.net"; class Inner { public void innerTest() { System.out.println(TOTAL_NUMBER); System.out.println(id); // System.out.println(str);不合法,只能訪問本地方法的final變量System.out.println( age); } } new Inner().innerTest(); } public static void main(String[] args) { Outer outer = new Outer(); outer.func(); }}
運行結果:
512315
匿名內部類
匿名內部類是局部內部類的一種特殊形式,也就是沒有變量名指向這個類的實例,而且具體的類實現會寫在這個內部類裡面。
注意:匿名類必須繼承一個父類或實現一個接口。
不使用匿名內部類來實現抽象方法:
abstract class Person { public abstract void eat();}class Child extends Person { public void eat() { System.out.println("eat something"); }}public class Demo { public static void main(String[] args ) { Person p = new Child(); p.eat(); }}
運行結果:
eat something
可以看到,我們用Child繼承了Person類,然後實現了Child的一個實例,將其向上轉型為Person類的引用。但是,如果此處的Child類只使用一次,那麼將其編寫為獨立的一個類豈不是很麻煩?
這個時候就引入了匿名內部類。使用匿名內部類實現:
abstract class Person { public abstract void eat();}public class Demo { public static void main(String[] args){ // 繼承Person 類new Person() { public void eat() { System.out.println(" eat something"); } }.eat(); }}
可以看到,匿名類繼承了Person 類並在大括號中實現了抽像類的方法。
內部類的語法比較複雜,實際開發中也較少用到,本教程不打算進行深入講解,各位讀者也不應該將內部類作為學習Java的重點。