可以將一個類的定義放在另一個類的定義內部,這就是內部類。
如果想從外部類的非靜態方法之外的任意位置創建某個內部類的對象,那麼必須像在main()
方法中那樣,具體的指明這個對象的類型:OuterClassName.InnerClassName
當生成一個內部類的時候,它能訪問其他外為對象的所有成員,此外,內部類還擁有其他外圍類的所有元素的訪問權。
這是如何做到的呢?
當某個外圍類創建一個內部類對象的時候,此內部類對象必定秘密的捕獲一個指向那個外圍來對象的應用。然後,在你訪問次外圍類的成員時,就是那個引用來選擇外圍類的成員。這部分工作有編譯器來幫我們處理。
如果你要生成對外部類對象的引用,可以使用外部類的名字後面跟上遠點和this。例如: return OuterClassNeme.this;
當你想要告知某些對象,去創建其某個內部類的對象,必須在new表達式中提供對其他外部類對象的引用,這需要使用.new 語法
OuterClass oc = new OuterClass();
OuterClass.InnerClass ic = oc.new InnerClass();
從類的設計角度看,private內部類給類的設計者提供了一種途徑,通過這樣的方式可以完全阻止任何依賴於類型的編碼,並且完全隱藏了實現的細節。因為打當內部類向上轉型成其基類,尤其是轉型成一個接口的時候,內部類阻止了了客戶端在使用過程中將對象向下轉型,因為不知道其名字。
public class Parcel7b{
class MyContents implements Contents{
private int i = 11;
public int value() {return i;}
}
public Contents contents(){return new MyContents;}
public static void main(String[] args){
Parcel7b p = new Parcel7();
Contents c = p.Contents();
}
}
上述內部類的聲明方式如果轉化成匿名內部類就是下面這個樣子.
public class Parcel7{
public Contests contents(){
return new Contents(){
private int i = 11;
public int value(){return i;
}
};
}
public static void main(String[] args){
Parcel7 p = new Parcel7();
Contents c = p.Contents();
}
}
看起來就是這個樣子的:在你想創建一個對象的時候,插入了這個對象對應的類定義方式。
匿名內部類與正規的繼承相比有些受限,因為匿名內部類既可以擴展類,也可以擴展接口,但是不能兩者兼備,而且如果是實現接口,也只能實現一個接口
這樣有什麼好處呢?可以用來簡化工廠模式的實現。P187&&P199
將工廠具名類以匿名內部類的形式放在產品類的內部,這樣皆可以省去創建工廠具名類的功夫,只需要單一的工廠對象就可以啦。
在Android中,我們定義線程的方式就是匿名內部類:
Thread t = new Thread() {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
}
};
t.start();
如果不需要內部類對象與其外圍類對象有聯系,那麼可以將內部類聲明為static,通常稱之為嵌套類。嵌套類意味著:
1.要創建嵌套類對象,並不需要其外圍類對象。使用內部類最吸引人的原因是:
每個內部類都能獨立的繼承一個(接口)的實現,所以無論外圍類是否已經集成了某個(接口)的實現,對於內部類沒有影響。這種屬性對於多重繼承來說,無疑是一種神器。
不只對於接口,假設你想繼承兩個或者三個類,外部類只能繼承一個,剩下的而就可以交給內部類來實現,因為內部類可以持有外部類的引用,所以可以使用繼承到的方法來操作外部類的數據,也就是說實現了多重繼承。在《Thinking in Java》中舉了一個通過內部類實現繼承迭代器的方式。見P192
最後放一個簡單的例子:
abstract class InnerAny{
abstract void out();
}
public class Outer{
private int i = 0;
class Inner{
int i = 8;
public void out(){
System.out.println(this.i);
System.out.println(Outer.this.i);
}
}
static class InnerStaic{
static int i = 1;
public InnerStaic(Outer p){
i = p.i;
}
}
public InnerAny ia(){
return new InnerAny(){
public void out(){
Outer.this.i++;
System.out.println(Outer.this.i);
}
};
}
public static void main(String[] args){
Outer p = new Outer();
System.out.println(p.i);
//普通內部類
Outer.Inner in = p.new Inner();
in.out();
p.i++;
//靜態內部類
InnerStaic is = new InnerStaic(p);
System.out.println(is.i);
p.i++;
System.out.println(Outer.InnerStaic.i);
in.out();
//匿名內部類
InnerAny ia = p.ia();
ia.out();
}
}
輸出是:0 8 0 1 1 8 2 3