Java的內部類可以獲得其外圍類的所有成員存取權限,可以很方便的對外圍類進行操作。非static內部類都含有一個隱藏的外圍類引用,這個引用可以通過 OuterClass.this 來獲得使用。通常如果我們的一組操作需要遵循某些規範(例如介面,抽象類別),就可以把這一組操作封裝成一個內部類來供外部使用,而又不會脫離外圍類。參見如下代碼:
public interface Selector<E> { boolean hasNext(); E next();}public class Sequence { private int[] seq; private Selector<Integer> obverseSelector; // 正序遍曆器 private Selector<Integer> reverseSelector; // 逆序遍曆器 public Sequence(int[] seq) { this.seq = seq; obverseSelector = new Selector<Integer>() { int counter = -1; @Override public Integer next() { return Sequence.this.seq[counter]; } @Override public boolean hasNext() { return (++counter < Sequence.this.seq.length); } }; reverseSelector = new Selector<Integer>() { int counter = Sequence.this.seq.length; @Override public Integer next() { return Sequence.this.seq[counter]; } @Override public boolean hasNext() { return (--counter >= 0); } }; } public Selector<Integer> getObverseSelector() { return obverseSelector; } public Selector<Integer> getReverseSelector() { return reverseSelector; }}public class Test { public static void main(String args[]) { int[] a = {1, 2, 3, 4, 5}; Sequence sequence = new Sequence(a); Selector<Integer> obSelector = sequence.getObverseSelector(); Selector<Integer> reSelector = sequence.getReverseSelector(); while (obSelector.hasNext()) { System.out.print(obSelector.next() + " "); } System.out.println(); while (reSelector.hasNext()) { System.out.print(reSelector.next() + " "); } }}
這個例子通過內部類實現Selector介面,讓Sequence類擁有屬於自己的正序遍曆器和逆序遍曆器。注意匿名內部類如果需要訪問外圍類的成員,需要使用 Outer.this 首碼來訪問。
可以想象如果不用內部類來實現遍曆器會有什麼不同,如果我們不用內部類來實現,就必須定義個Selector的具體類,並且將Sequence類的seq數組作為參數傳進去。如果說需要將Selector作為一個共用的遍曆器,可以這麼做,但如果遍曆器是針對Sequence類來實現的,則用內部類更為方便。
下面的代碼是使用非匿名內部類實現的Selector
public class Sequence2 { private int[] seq; public Sequence2(int[] seq) { this.seq = seq; } public class ObverseSelecter implements Selector<Integer> { int counter = -1; @Override public Integer next() { return seq[counter]; } @Override public boolean hasNext() { return (++counter < seq.length); } } public class ReverseSelecter implements Selector<Integer> { int counter = seq.length; @Override public Integer next() { return seq[counter]; } @Override public boolean hasNext() { return (--counter >= 0); } }}public class Test { public static void main(String args[]) { int[] a = {1, 2, 3, 4, 5}; Sequence2 sequence2 = new Sequence2(a); Selector<Integer> obSelector2 = sequence2.new ObverseSelecter(); Selector<Integer> reSelector2 = sequence2.new ReverseSelecter(); while (obSelector2.hasNext()) { System.out.print(obSelector2.next() + " "); } System.out.println(); while (reSelector2.hasNext()) { System.out.print(reSelector2.next() + " "); } }}
此處僅需要注意一下產生遍曆的時候的new文法 sequence2.new ,容易看出內部類的執行個體其實是和外圍類的執行個體緊密相關的,正如匿名內部類的 Outer.this 文法一樣
值得一提的是局部內部類如果要使用局部變數,那麼局部變數必須為final,否則編譯會不通過,參見如下代碼
public interface Flyable { void fly();}public class FinalTest { public static Flyable getFlyable(int speed) { final int finalSpeed = speed * 2; return new Flyable() { @Override public void fly() { System.out.println("I can fly with speed " + finalSpeed + " km/h"); } }; } public static void main(String[] args) { Flyable flyable = getFlyable(50); flyable.fly(); }}
可見finalSpeed為final變數,為什麼有這種要求呢?
是因為局部變數的生命週期僅僅在方法執行範圍內,當方法執行完畢,局部變數自然就被銷毀。但是內部類卻作為一個執行個體被返回來了,如果說這個內部類執行個體以後還需要訪問這個已銷毀的局部變數,顯然是不可以的。所以在內部類裡需要訪問的局部變數都會定義成常量,一起被編譯進內部類裡。