java程序語言允許你在一個類里面再聲明另一個類,這樣的類成為嵌套類,說明如下:
class OuterClass { ... class NestedClass { ... } }
術(shù)語:嵌套類分為兩種:靜態(tài)或非靜態(tài)。嵌套類聲明為static稱為靜態(tài)嵌套類。非靜態(tài)嵌套類都稱為內(nèi)部類。
class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}
一個嵌套類是它的封裝類的成員。非靜態(tài)嵌套類可以訪問它的封裝類的其他成員,即使這些成員聲明是private。靜態(tài)嵌套類不能訪問封裝類的其他成員。就像外部類的一個成員一樣,嵌套類可以聲明為private,public,protected,包內(nèi)私有(回顧外部類只能聲明為public或者是包內(nèi)私有)
為什么使用嵌套類
使用嵌套類,其中有幾個令人信服的理由:
它是一個在一個地方使用類的邏輯分組的方法
它加強封裝
嵌套類可以促進(jìn)更可讀性,可維護性的代碼。
類的邏輯分組—如果一個類只是被其他一個類使用,那么合乎邏輯的是把它嵌套到該類,讓這兩個類在一起。嵌套這樣的幫助類可以讓包更加精簡。
加強封裝—考慮兩個頂級類,A和B,如果B需要訪問A的private成員,通過在A類隱藏B類,那么即使A的成員聲明為private,那么B也可以訪問它們。更多的是,B本身也可以隱藏于外部。
更可讀性,可維護性的代碼—在頂級類里嵌套小類,讓代碼更靠近使用的地方。
靜態(tài)嵌套類
和類方法,類變量一樣,一個靜態(tài)嵌套類是和它的外部類關(guān)聯(lián)的。就像靜態(tài)類方法一樣,一個靜態(tài)嵌套類不能直接引用封裝類的實例變量或者方法—它只能通過封裝類的引用訪問它們。
注意:一個靜態(tài)嵌套類訪問它的封裝類(和其他類)的實例成員,就像訪問其他頂級類一樣。事實上,一個靜態(tài)嵌套類就像一個頂級類,只是行為上嵌套在另一個頂級類里而已,達(dá)到打包方便的目的。
靜態(tài)嵌套類是使用封裝類的名字訪問:
OuterClass.StaticNestedClass
例如,創(chuàng)建一個靜態(tài)嵌套類的對象,語法是:
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
內(nèi)部類
如實例方法和實例字段一樣,一個內(nèi)部類是和封裝類的實例關(guān)聯(lián)的,并且可以直接訪問這個對象的成員和方法。正是因為一個內(nèi)部類是和實例關(guān)聯(lián)的,所以它不能定義任何靜態(tài)成員。
內(nèi)部類的對象實例存在于外部類的實例,考慮下面的類:
class OuterClass { ... class InnerClass { ... } }
一個內(nèi)部類的實例,盡可以存在于外部類的實例中,并且可以直接訪問封裝實例的方法和字段。下圖說明了這個想法:
一個內(nèi)部類的實例存在于外部類的實例
實例化內(nèi)部類之前,你首先要實例化外部類。然后基于外部類的對象創(chuàng)建內(nèi)部類對象,語法是:
還有,有兩種特別的內(nèi)部類,局部類和匿名類(也可以成為匿名內(nèi)部類)。這兩者會在后面討論。
內(nèi)部類例子
為了演示內(nèi)部類的使用,讓我們思考一個數(shù)組。接下來的例子,我們會創(chuàng)建一個數(shù)組,填充為整數(shù),輸出的數(shù)組的索引值是升序的。
下面的DataStructure類包括:
DataStructure外部類,包含了添加整數(shù)到內(nèi)部數(shù)組的方法,輸出數(shù)組里的索引值
InnerEvenIterator內(nèi)部類,類似java的標(biāo)準(zhǔn)迭代器。迭代器用于遍歷一個數(shù)據(jù)結(jié)果,典型的是判斷是否到了最后一個元素,檢索當(dāng)前元素,移動到下一個元素。
在main方法里實例化DataStructure對象,使用它填充數(shù)組arrayOfInts為一系列整數(shù)(0, 1, 2, 3, etc.),然后調(diào)用一個printEven 方法,輸出arrayOfInts的索引值。
public class DataStructure {
// create an array
private final static int SIZE = 15;
private int[] arrayOfInts = new int[SIZE];
public DataStructure() {
// fill the array with ascending integer values
for (int i = 0; i < SIZE; i++) {
arrayOfInts[i] = i;
}
}
public void printEven() {
// print out values of even indices of the array
InnerEvenIterator iterator = this.new InnerEvenIterator();
while (iterator.hasNext()) {
System.out.println(iterator.getNext() + " ");
}
}
// inner class implements the Iterator pattern
private class InnerEvenIterator {
// start stepping through the array from the beginning
private int next = 0;
public boolean hasNext() {
// check if a current element is the last in the array
return (next <= SIZE - 1);
}
public int getNext() {
// record a value of an even index of the array
int retValue = arrayOfInts[next];
//get the next even element
next += 2;
return retValue;
}
}
public static void main(String s[]) {
// fill the array with integer values and print out only
// values of even indices
DataStructure ds = new DataStructure();
ds.printEven();
}
}
輸出是:
0 2 4 6 8 10 12 14
注意InnerEvenIterator是直接引用DataStructure對象的實例變量arrayOfInts。
內(nèi)部類可用來實現(xiàn)幫助類,就像上面的例子。如果你計劃處理用戶接口事件,你需要指導(dǎo)如何使用內(nèi)部類,因為事件處理機制中,內(nèi)部類是廣泛使用的。
局部和匿名內(nèi)部類
有兩種良性的內(nèi)部類。你可以在方法體內(nèi)聲明一個內(nèi)部類。這樣的類成為局部內(nèi)部類。你也可以在方法體內(nèi),聲明一個沒有名字的內(nèi)部類,這種類就是匿名內(nèi)部類了。我們將會在java高級編程遇到它。
修飾符
可以為內(nèi)部類使用修飾符,就像外部類成員那么使用。例如,可以使用特殊訪問—private,public,protected—限制訪問內(nèi)部類的方式,就像和其他類成員的使用方式一樣。