|
Java內(nèi)部類(Inner Class)詳解 簡(jiǎn)單的說(shuō),內(nèi)部(inner)類指那些類定義代碼被置于其它類定義中的類;而對(duì)于一般的、類定義代碼不嵌套在其它類定義中的類,稱為頂層(top-level)類。對(duì)于一個(gè)內(nèi)部類,包含其定義代碼的類稱為它的外部(outer)類。 1 Static member class(靜態(tài)成員類) 類聲明中包含“static”關(guān)鍵字的內(nèi)部類。如以下示例代碼, Inner1/Inner2/Inner3/Inner4就是Outer的四個(gè)靜態(tài)成員類。靜態(tài)成員類的使用方式與一般頂層類的使用方式基本相同。 public class Outer{ //just like static method, static member class has public/private/default access privilege levels //access privilege level: public public static class Inner1 { public Inner1() { //Static member inner class can access static method of outer class staticMethod(); //Compile error: static member inner class can not access instance method of outer class //instanceMethod(); } } //access privilege level: default static class Inner2 { } //access privilege level: private private static class Inner3 { //define a nested inner class in another inner class public static class Inner4 { } } private static void staticMethod() { //cannot define an inner class in a method /*public static class Inner4() { }*/ } private void instanceMethod() { //private static member class can be accessed only in its outer class definition scope Inner3 inner3 = new Inner3(); //how to use nested inner class Inner3.Inner4 inner4 = new Inner3.Inner4(); } } class Test { Outer.Inner1 inner1 = new Outer.Inner1(); //Test and Outer are in the same package, so Inner2 can be accessed here Outer.Inner2 inner2 = new Outer.Inner2(); //Compile error: Inner3 cannot be accessed here //Outer.Inner3 inner3 = new Outer.Inner3(); } 1.1 靜態(tài)成員類特性 靜態(tài)成員類可訪問(wèn)外部類的任一靜態(tài)字段或靜態(tài)方法 像靜態(tài)方法或靜態(tài)字段一樣,靜態(tài)成員類有public/private/default權(quán)限修飾符 1.2 靜態(tài)成員類約束 靜態(tài)成員類不能與外部類重名 像外部類的靜態(tài)方法一樣,不能直接訪問(wèn)外部類的實(shí)例字段和實(shí)例方法 靜態(tài)成員類只能定義于外部類的頂層代碼或外部類其它靜態(tài)成員類的頂層代碼中(嵌套定義);不能定義于外部類的某個(gè)函數(shù)中。 1.3 新增語(yǔ)法 如示例代碼所示,可以以“OuterClass.InnerClass”的方式來(lái)引用某個(gè)內(nèi)部類。 1.4 什么時(shí)候使用靜態(tài)成員類 B為A的輔助類,且只為A所用時(shí),可將B定義為A的靜態(tài)成員類。例如JDK中的LinkedList類就有Entry靜態(tài)成員類: public class LinkedList<E> extends AbstractSequentialList<E> …; private static class Entry<E> { E element; Entry<E> next; Entry<E> previous; Entry(E element, Entry<E> next, Entry<E> previous) { this.element = element; this.next = next; this.previous = previous; } } …; } 顯然,Entry用來(lái)表示LinkedList中的一個(gè)結(jié)點(diǎn),只被LinkedList自身使用。 2 Member class(成員類) 一個(gè)靜態(tài)成員類,若去掉“static”關(guān)鍵字,就成為成員類。如下示例代碼,Inner1/Inner2/Inner3/Inner4就是Outer的四個(gè)成員類 public class Outer { //just like instance method, member class has public/private/default access privilege levels private int data; //access privilege level: public public class Inner1 { private int data; private int data1; public Inner1() { //member class can access its outer class' instance field directly data1 = 1; //itself data field data = 1; //its outer class instance field Outer.this.data = 1; } } //access privilege level: default class Inner2 { //can not define static filed, method, class in member class //static int j = 1; //but, "static final" compound is allowed static final int CONSTANT = 1; } //access privilege level: private private class Inner3 { public class Inner4 { } } //in fact, Inner5 is not a member class but a static member class interface Inner5 { } private static void staticMethod() { //can not create a member class instance directly in outer class' static method //Inner1 inner1 = new Inner1(); } private void instanceMethod() { //can create a member class instance in outer class' instance method Inner1 inner1 = new Inner1(); } } class Test { public Test() { //cannot create member class instance directly in class other than outer class //Outer.Inner2 inner2 = new Outer.Inner2(); //create a member class instance outside it's outer class Outer outer = new Outer(); Outer.Inner1 inner1 = outer.new Inner1(); } } 2.1 成員類特性 · 類似于外部類的實(shí)例函數(shù),成員類有public/private/default權(quán)限修飾符 · 一個(gè)成員類實(shí)例必然所屬一個(gè)外部類實(shí)例,成員類可訪問(wèn)外部類的任一個(gè)實(shí)例字段和實(shí)例函數(shù)。 2.2 成員類約束 成員類不能與外部類重名 不能在成員類中定義static字段、方法和類(static final形式的常量定義除外)。因?yàn)橐粋€(gè)成員類實(shí)例必然與一個(gè)外部類實(shí)例關(guān)聯(lián),這個(gè)static定義完全可以移到其外部類中去 成員類不能是接口(interface)。因?yàn)槌蓡T類必須能被某個(gè)外部類實(shí)例實(shí)例化,而接口是不能實(shí)例化的。事實(shí)上,如示例代碼所示,如果你以成員類的形式定義一個(gè)接口,該接口實(shí)際上是一個(gè)靜態(tài)成員類,static關(guān)鍵字對(duì)inner interface是內(nèi)含(implicit)的。 2.3 新增語(yǔ)法 一個(gè)成員類實(shí)例必然所屬于其外部類的一個(gè)實(shí)例,那么如何在成員類內(nèi)部獲得其所屬外部類實(shí)例呢?如示例代碼所示,采用“OuterClass.this”的形式。 2.4 指定內(nèi)部類實(shí)例所屬的外部類實(shí)例 內(nèi)部類實(shí)例可在其外部類的實(shí)例方法中創(chuàng)建,此新創(chuàng)建內(nèi)部類實(shí)例所屬的外 部類實(shí)例自然就是創(chuàng)建它的外部類實(shí)例方法對(duì)應(yīng)的外部類實(shí)例。 另外,如示例代碼所示,對(duì)于給定的一個(gè)外部類實(shí)例outerClass,可以直接創(chuàng)建其內(nèi)部類實(shí)例,語(yǔ)法形式為: OuterClass.InnerClass innerClass = outerClass.new InnerClass(); 2.5 什么時(shí)候使用成員類 成員類的顯著特性就是成員類能訪問(wèn)它的外部類實(shí)例的任意字段與方法。方便一個(gè)類對(duì)外提供一個(gè)公共接口的實(shí)現(xiàn)是成員類的典型應(yīng)用。 以JDK Collection類庫(kù)為例,每種Collection類必須提供一個(gè)與其對(duì)應(yīng)的Iterator實(shí)現(xiàn)以便客戶端能以統(tǒng)一的方式遍歷任一 Collection實(shí)例。每種Collection類的Iterator實(shí)現(xiàn)就被定義為該Collection類的成員類。例如JDK中 AbstractList類的代碼片斷: public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> { private class Itr implements Iterator<E> { ………; } public Iterator<E> iterator() { return new Itr(); } } 因?yàn)槎x在AbstractList中的Itr可訪問(wèn)AbstractList中的任意字段和方法,所以很方便實(shí)現(xiàn)Iterator,無(wú)需AbstractList對(duì)外暴露更多的接口。 試想,如果沒(méi)有成員類機(jī)制,只有在AbastractList源碼之外定義一個(gè)實(shí)現(xiàn)Iterator的類Itr,該類有一個(gè)AbstractList實(shí)例成員list,為了Itr能獲取list的內(nèi)部信息以便實(shí)現(xiàn)遍歷,AbstractList必然要向Itr開(kāi)放額外的訪問(wèn)接口。 3 Local class(局部類) 對(duì)一個(gè)靜態(tài)成員類,去掉其聲明中的“static”關(guān)鍵字,將其定義移入其外部類 的靜態(tài)方法或靜態(tài)初始化代碼段中就成為了局部靜態(tài)成員類。 對(duì)一個(gè)成員類,將其定義移入其外部類的實(shí)例方法或?qū)嵗跏蓟a中就成為了局部成員類。 局部靜態(tài)成員類與靜態(tài)成員類的基本特性相同。例如,都只能訪問(wèn)外部類的靜態(tài)字段或方法,但不能訪問(wèn)外部類的實(shí)例字段和實(shí)例方法等。 局部成員類與成員類的基本特性相同。例如,局部成員類實(shí)例必屬于其外部類的一個(gè)實(shí)例,可通過(guò)OuterClass.this引用其外部類實(shí)例等。 另外,局部類也有其自己的特性,如以下代碼所示: public class Outer { private int instanceField; private static int staticField; //define a local member class in instance code block { int localVirable1 = 0; final int localVirable2 = 1; class Inner1 { public Inner1() { //can access its outer class' field and method directly instanceField = 1; //use OuterClass.this to get its corresponding outer class instance Outer.this.instanceField = 1; //can not access the not final local virable in its containing code block //System.out.print(localVirable1); //can access the final local virable in its containing code block System.out.print(localVirable2); } } //local class can not have privilege modifier /*public class inner2 { }*/ } // define a local static member class in static code block static { class Inner2 { public Inner2() { staticField = 1; //can not access instance field and method in a local static member class //intanceField = 2; } } } public void intanceMethod() { //define a local class in its out class' instance method class Inner3 { } //local class is visible only in its containning code block //Outer.Inner2 inner2; } private static void staticMethod() { //define a local static member class in its out class' static method class Inner4 { public Inner4() { staticField = 2; } } //can not define a interface as a local class /*interface I { }*/ } } 3.1 局部類特性 如示例代碼所示,局部類能且只能訪問(wèn)其所屬代碼段中的聲明為final的局部 變量。為什么只能訪問(wèn)聲明為final的局部變量呢?我們知道,局部變量在其所屬的代碼段(譬如某個(gè)函數(shù))執(zhí)行完畢后就會(huì)被回收,而一個(gè)局部類的實(shí)例卻可以在其類定義所屬代碼段執(zhí)行完畢后依然存在,如果它可操控非final的局部變量,用戶就可以通過(guò)該實(shí)例修改已不存在的局部變量,無(wú)意義。 3.2 局部類約束 如示例代碼所示,內(nèi)部類只在定義它的代碼段中可見(jiàn),不能在它所屬代碼段之外的代碼中使用;因此也就沒(méi)有public/private/default權(quán)限修飾符(無(wú)意義) 不能以局部類形式定義一個(gè)接口。局部類只在其所屬代碼段中可見(jiàn),定義這樣的接口無(wú)意義 局部類類名不能與其外部類類名重復(fù) 3.3 什么時(shí)候使用局部類 局部類大部分以匿名類的形式使用。 4 Anonymous class(匿名類) 沒(méi)有類名的局部類就是匿名類。用一條語(yǔ)句完成匿名類的定義與實(shí)例創(chuàng)建。例 如如下代碼: public class Outer { public void instanceMethod() { //define a nonymous class which implements Action interface and creat an instance of it Action action = new Action() { public void doAction() { System.out.println("a simple anonymous class demo"); }}; action.doAction(); //define a nonoymous class which extends BaseClass and create an instance of it new BaseClass(5) { public void printData(){ System.out.println("data = " + getData()); } }.printData(); //"data = 5" will be outputed } } interface Action { void doAction(); } class BaseClass { private int data; public BaseClass (int data) { this.data = data; } public int getData() { return data; } } 4.1 匿名類特性與約束 匿名類是一種特殊的局部類。局部類的特性與約束都適用與它。 4.2 新增語(yǔ)法 4.2.1 繼承自某個(gè)基類的匿名類 new class-name ( [ argument-list ] ) { class-body } 創(chuàng)建匿名類實(shí)例時(shí),“argument-list”將被傳入其基類(即class-name)對(duì)應(yīng)的構(gòu)造函數(shù)。 4.2.2 實(shí)現(xiàn)某個(gè)接口的匿名類 new interface-name () { class-body } 4.3 什么時(shí)候使用匿名類 該類定義代碼段很短 只需要?jiǎng)?chuàng)建該類的一個(gè)實(shí)例 類的定義代碼與類的使用代碼緊鄰 使用匿名不影響代碼的易讀性 譬如,如下實(shí)現(xiàn)類似與c的callback功能的代碼就是匿名類的典型應(yīng)用: File f = new File("/src"); // The directory to list // Now call the list() method with a single FilenameFilter argument // Define and instantiate an anonymous implementation of FilenameFilter // as part of the method invocation expression. String[] filelist = f.list(new FilenameFilter() { public boolean accept(File f, String s) { return s.endsWith(".java"); } }); // Don't forget the parenthesis and semicolon that end the method call! |
|
|