簡單的說,內部(inner)類指那些類定義代碼被置於其它類定義中的類;而對於一般的、類定義代碼不嵌套在其它類定義中的類,稱為頂層(top-level)類。對於一個內部類,包含其定義代碼的類稱為它的外部(outer)類。
1 Static member class(靜態成員類)
類聲明中包含“static”關鍵字的內部類。如以下示例代碼,
Inner1/Inner2/Inner3/Inner4就是Outer的四個靜態成員類。靜態成員類的使用方式與一般頂層類的使用方式基本相同。
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->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 靜態成員類特性
靜態成員類可訪問外部類的任一靜態字段或靜態方法
像靜態方法或靜態字段一樣,靜態成員類有public/private/default權限修飾符
1.2 靜態成員類約束
靜態成員類不能與外部類重名
像外部類的靜態方法一樣,不能直接訪問外部類的實例字段和實例方法
靜態成員類只能定義於外部類的頂層代碼或外部類其它靜態成員類的頂層代碼中(嵌套定義);不能定義於外部類的某個函數中。
1.3 新增語法
如示例代碼所示,可以以“OuterClass.InnerClass”的方式來引用某個內部類。
1.4 什麼時候使用靜態成員類
B為A的輔助類,且只為A所用時,可將B定義為A的靜態成員類。例如JDK中的LinkedList類就有Entry靜態成員類:
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->public class LinkedList
…;
private static class Entry
E element;
Entry
Entry
Entry(E element, Entry
this.element = element;
this.next = next;
this.previous = previous;
}
}
…;
}
顯然,Entry用來表示LinkedList中的一個結點,只被LinkedList自身使用。
2 Member class(成員類)
一個靜態成員類,若去掉“static”關鍵字,就成為成員類。如下示例代碼,Inner1/Inner2/Inner3/Inner4就是Outer的四個成員類
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->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 成員類特性
類似於外部類的實例函數,成員類有public/private/default權限修飾符
一個成員類實例必然所屬一個外部類實例,成員類可訪問外部類的任一個實例字段和實例函數。
2.2 成員類約束
成員類不能與外部類重名
不能在成員類中定義static字段、方法和類(static final形式的常量定義除外)。因為一個成員類實例必然與一個外部類實例關聯,這個static定義完全可以移到其外部類中去
成員類不能是接口(interface)。因為成員類必須能被某個外部類實例實例化,而接口是不能實例化的。事實上,如示例代碼所示,如果你以成員類的形式定義一個接口,該接口實際上是一個靜態成員類,static關鍵字對inner interface是內含(implicit)的。
2.3 新增語法
一個成員類實例必然所屬於其外部類的一個實例,那麼如何在成員類內部獲得其所屬外部類實例呢?如示例代碼所示,采用“OuterClass.this”的形式。
2.4 指定內部類實例所屬的外部類實例
內部類實例可在其外部類的實例方法中創建,此新創建內部類實例所屬的外
部類實例自然就是創建它的外部類實例方法對應的外部類實例。
另外,如示例代碼所示,對於給定的一個外部類實例outerClass,可以直接創建其內部類實例,語法形式為:
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
2.5 什麼時候使用成員類
成員類的顯著特性就是成員類能訪問它的外部類實例的任意字段與方法。方便一個類對外提供一個公共接口的實現是成員類的典型應用。
以JDK Collection類庫為例,每種Collection類必須提供一個與其對應的Iterator實現以便客戶端能以統一的方式遍歷任一Collection實例。每種Collection類的Iterator實現就被定義為該Collection類的成員類。例如JDK中AbstractList類的代碼片斷:
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->public abstract class AbstractList
private class Itr implements Iterator
………;
}
public Iterator
return new Itr();
}
}
因為定義在AbstractList中的Itr可訪問AbstractList中的任意字段和方法,所以很方便實現Iterator,無需AbstractList對外暴露更多的接口。
試想,如果沒有成員類機制,只有在AbastractList源碼之外定義一個實現Iterator的類Itr,該類有一個AbstractList實例成員list,為了Itr能獲取list的內部信息以便實現遍歷,AbstractList必然要向Itr開放額外的訪問接口。
3 Local class(局部類)
對一個靜態成員類,去掉其聲明中的“static”關鍵字,將其定義移入其外部類
的靜態方法或靜態初始化代碼段中就成為了局部靜態成員類。
對一個成員類,將其定義移入其外部類的實例方法或實例初始化代碼中就成為了局部成員類。
局部靜態成員類與靜態成員類的基本特性相同。例如,都只能訪問外部類的靜態字段或方法,但不能訪問外部類的實例字段和實例方法等。
局部成員類與成員類的基本特性相同。例如,局部成員類實例必屬於其外部類的一個實例,可通過OuterClass.this引用其外部類實例等。
另外,局部類也有其自己的特性,如以下代碼所示:
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->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 局部類特性
如示例代碼所示,局部類能且只能訪問其所屬代碼段中的聲明為final的局部
變量。為什麼只能訪問聲明為final的局部變量呢?我們知道,局部變量在其所屬的代碼段(譬如某個函數)執行完畢後就會被回收,而一個局部類的實例卻可以在其類定義所屬代碼段執行完畢後依然存在,如果它可操控非final的局部變量,用戶就可以通過該實例修改已不存在的局部變量,無意義。
3.2 局部類約束
如示例代碼所示,內部類只在定義它的代碼段中可見,不能在它所屬代碼段之外的代碼中使用;因此也就沒有public/private/default權限修飾符(無意義)
不能以局部類形式定義一個接口。局部類只在其所屬代碼段中可見,定義這樣的接口無意義
局部類類名不能與其外部類類名重復
3.3 什麼時候使用局部類
局部類大部分以匿名類的形式使用。
4 Anonymous class(匿名類)
沒有類名的局部類就是匿名類。用一條語句完成匿名類的定義與實例創建。例
如如下代碼:
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->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;
}
}