在JAVA中,內部類似乎是一種名字隱藏和組織代碼的一種形式,但內部類還有另一個最重要的用途:當生成一個內部類的對象時,此對象與製造它的外圍對象之間構建了一種特殊的聯繫,內部類對象能夠訪問外圍類對象的所有成員,而不需要任何條件。此外,內部類還擁有外圍類所有元素的訪問權。看如下一段代碼:
package access;
interface Selector{
boolean end();
Object current();
void next();
}
public class Squence {
private Object[] items;
private int next = 0;
public Squence(int size){
items = new Object[size];
}
public void add(Object x){
if(next < items.length)
items[next++] = x;
}
private class SequenceSelector implements Selector{
private int i = 0;
public boolean end(){
return i == items.length;
}
public Object current(){
return items[i];
}
public void next(){
if(i < items.length)
i++;
}
}
public Selector selector(){
return new SequenceSelector();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Squence sequence = new Squence(10);
for(int i = 0;i<10;i++)
sequence.add(Integer.toString(i));
Selector selector = sequence.selector();
while(!selector.end()){
System.out.print(selector.current() + " ");
selector.next();
}
}
}
此程序的運行結果爲:
在上述例子當中,Squence類是一個固定大小的Object數組,以類的形式包裝了起來而已。add方法用來在序列末端加入新的Object。若想獲取Squence中的每個對象,可以使用Selector接口。因爲Selector是一個接口,所以別的類可以按它們自己的方式來實現這個接口,並且別的方法能以此接口作爲參數來生成更加通用的代碼。
SequenceSelector是一個內部類,但注意end方法、current方法、和next方法,這三個方法均調用了外圍類的private訪問權限的objects,所以說內部類可以無條件的訪問外圍類的任何成員及方法,無論訪問權限是什麼樣的。
原理在於當某個外圍類創建了一個內部類對象時,內部類對象必定會祕密捕捉一個指向那個外圍類對象的引用,然後在我們訪問外圍類的成員時就是用這個引用來選擇外圍類的成員。內部類的對象只能在與其外圍類的對象相關聯的情況下才能被創建,構建內部類對象的時候,需要一個指向外圍類對象的引用,如果編譯器訪問不到這個引用則會報錯。
如果我們需要生成對外部類對象的引用,可以使用外部類的名字後面緊跟“.this”,這樣產生的引用自動具有正確的類型。比如如下一段代碼:
package access;
public class DotThis {
void f(){
System.out.println("DotThis.f()");
}
public class Inner{
public DotThis outer(){
return DotThis.this;
}
}
public Inner inner(){
return new Inner();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
DotThis dt = new DotThis();
DotThis.Inner dti = dt.inner();
dti.outer().f();
}
}
此程序運行結果爲:
有時我們可能想要告知某些其他對象,去創建某個內部類的對象,要實現此目的,必須在new表達式中提供對其他外部類對象的引用,這時需要使用到“.new”,比如如下一段代碼:
package access;
public class DotNew {
public class Inner{}
public static void main(String[] args) {
// TODO Auto-generated method stub
DotNew dn = new DotNew();
DotNew.Inner dni = dn.new Inner();
}
}
要想直接創建內部類對象,我們不能按照我們想象的方式去引用外部類名字DotNew,而是必須使用外部類的對象來創建內部類對象,在擁有外部類對象之前是無法創建內部類對象的,我們必須從外到內逐步創建,但如果創建的是嵌套類(靜態內部類),則不需要對外部類對象的引用。
下面看一個關於“.new ”應用於Parcel的實例:
package access;
public class Parcel3 {
class Contents{
private int i = 11;
public int value(){
return i;
}
}
class Destination{
private String label;
Destination(String whereTo){
label = whereTo;
}
String readLabel(){
return label;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Parcel3 p = new Parcel3();
Parcel3.Contents c = p.new Contents();
Parcel3.Destination d = p.new Destination("Tasmania");
}
}