1.內部類的繼承
因爲內部類的構造器必須連接到指向其外圍類對象的引用,所以在繼承內部類的時候,必須使用特殊的語法來明確說清它們之間的關聯:
public class WithInner {
class Inner{
}
}public class IntheritInner extends WithInner.Inner{
IntheritInner(WithInner wi){
wi.super();
}
public static void main(String[] args) {
WithInner withInner = new WithInner();
IntheritInner ii = new IntheritInner(withInner);
}
}
可以看到,IntheritInner只繼承自內部類,而不是外圍類。但是當要生成一個構造器時,默認的構造器並不算好,而且不能只是傳遞一個指向外圍類對象的引用。此外,必須在構造器內使用如下語法:enclosingClassReference.super();這樣才提供了必要的引用,纔不會報錯。
2.內部類可以爲覆蓋嗎
創建一個內部類,然後繼承其外圍類並重新定義此內部類,也就是“覆蓋”內部類,但是內部類就好像是外圍類的一個方法,其實並不起什麼作用。例子如下:
public class Egg {
private Yolk y;
protected class Yolk{
public Yolk() {
System.out.println("Egg.Yolk()");
}
}
public Egg() {
System.out.println("new Egg()");
y = new Yolk();
}
}
public class BigEgg extends Egg{
public class Yolk{
public Yolk() {
System.out.println("BigEgg.Yolk()");
}
}
public static void main(String[] args) {
new BigEgg();
}
}
輸出:new Egg()
Egg.Yolk()
這個例子說明,當繼承了某個外圍類的時候,內部類並沒有發生什麼特別神器的變化。這兩個內部類時完全獨立的兩個實體,各自在自己的命名空間內。
3.局部內部類
可以在代碼塊裏創建內部類,典型的方式是在一個方法體裏面創建內部類。局部內部類不能有訪問說明符,因爲它不是外圍類的一部分;但是它可以訪問當前代碼塊內的常量,以及此外圍類的所有成員。下面的例子對局部內部類與匿名內部類的創建進行了比較,例子如下:
public interface Counter {
int next();
}
public class LocalInnerClass {
private int count = 0;
Counter getCounter(final String name){
class LocalCounter implements Counter{
public LocalCounter(){
System.out.println("LocalCounter()");
}
@Override
public int next() {
System.out.println(name);
return count++;
}
}
return new LocalCounter();
}
Counter getCounter2(final String name){
return new Counter() {
{
System.out.println("Counter()");
}
@Override
public int next() {
System.out.println(name);
return count++;
}
};
}
public static void main(String[] args) {
LocalInnerClass lic = new LocalInnerClass();
Counter c1 = lic.getCounter("Local inner");
Counter c2 = lic.getCounter2("Anonymous inner");
for (int i = 0; i < 5; i++) {
System.out.println(c1.next());
}
for (int i = 0; i < 5; i++) {
System.out.println(c2.next());
}
}
}
Counter 返回的是系列中的下一個值。我們分別使用局部內部類和匿名內部類實現了這個功能,它們具有相同的行爲和能力。既然局部內部類的名字在方法外是不可見的,那爲什麼我們仍然使用局部內部類而不是匿名內部類呢?唯一的理由是,我們需要一個已命名的構造器,或者需要重載構造器,而匿名內部類只能用於實例初始化。所以使用局部內部類而不使用匿名內部類的另一個理由就是,需要不止一個該內部類的對象。
4.爲什麼加上final後的局部變量就可以在內部類中使用了?
因爲加上final後,編譯器是這樣處理內部類的:如果這個外部局部變量是常量,則在內部類代碼中直接用這個常量;如果是類的實例,則編譯器將產生一個內部類的構造參數,將這個final變量傳到內部類裏,這樣即使外部局部變量無效了,還可以使用,所以調用的實際是自己的屬性而不是外部類方法的參數或局部變量。這樣理解就很容易得出爲什麼要用final了,因爲兩者從外表看起來是同一個東西,實際上卻不是這樣,如果內部類改掉了這些參數的值也不可能影響到原參數,然而這樣卻失去了參數的一致性,因爲從編程人員的角度來看他們是同一個東西,如果編程人員在程序設計的時候在內部類中改掉參數的值,但是外部調用的時候又發現值其實沒有被改掉,這就讓人非常的難以理解和接受,爲了避免這種尷尬的問題存在,所以編譯器設計人員把內部類能夠使用的參數設定爲必須是final來規避這種莫名其妙錯誤的存在。