Java基礎內部類4-內部類進階

dav2100發表於2021-09-09

前言

除了前面介紹,內部類還有一些更高階的用法,下面就簡單的介紹一下

介面內部類

內部類除了可以定義在類的內部,也可以定義在介面裡面,用法與類類似

// Move.java

public interface Move {

    void run();
    void walk();

    class Run {

        public void move() {
            System.out.println("run");
        }
    }

    class Walk {
        public void move() {
            System.out.println("walk");
        }
    }
}

// AnimalMoveImpl.java
public class AnimalMoveImpl implements Move {
    @Override
    public void run() {
        new Run().move();
    }

    @Override
    public void walk() {
        new Walk().move();
    }
}

多層巢狀內部類訪問外圍類成員

內部類無論巢狀了多少層,內部類都是可以無條件的訪問外部的成員,包括private

public class MultiInner {
    private int val = 0;
    class Inner1 {
        {
            System.out.println(val);
        }
        class Inner2 {
            {
                System.out.println(val);
            }
            class Inner3 {
                {
                    System.out.println(val);
                }
            }
        }
    }
}

內部類繼承

這是一個比較有意思的事情

NOTE: 這裡說的內部類繼承不是內部類繼承其他類,而是其他類繼承內部類

class WithInner {
    class Inner {}
}

public class InheritInner extends WithInner.Inner {

}

在想象中應該是這樣寫,沒問題,但是如果在ide中敲程式碼,編譯器會報錯

No enclosing instance of type 'xxx.xxx.xxx.WithInner' is in scope

意思為沒有封閉型別的WithInner型別,在ide會提示一種方案是將Inner改為靜態內部類,這樣確實可以解決問題,但是如果不能用靜態內部類呢?

試想一下為什麼靜態內部類可以,而成員內部類會報錯,這兩者有什麼區別?

回頭看一下發現,成員內部類在建立的時候是要依賴外部類的例項物件,但是在第三方類繼承內部類的時候,沒有外部類物件,這樣就無法構成閉環,所以報錯。解決辦法也很簡單,在構造第三方類的時候,手動提供一個外部類物件,並對其初始化即可

public class InheritInner extends WithInner.Inner {
    InheritInner(WithInner wi) {
        wi.super();
    }

    public static void main(String[] args) {
        WithInner wi = new WithInner();
        InheritInner ii = new InheritInner(wi);
    }
}

內部類能被覆蓋嗎?

你覺得呢?

分析一下,內部類(以成員內部類來說)依賴於外部類,被編譯器編譯成WithInner$Inner.class,假如說有個WithInner的子類SubWithInner包含了一個同名的Inner類,這個會覆蓋父類中的Inner嗎?子類中的Inner被編譯成SubWithInner$Inner.class這明顯與父類中的類名不一樣。所以理論上是不會覆蓋的。實踐一下!

// Egg.java
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();
    }
}

// BigEgg.java
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

從輸出結果來看,確實沒有覆蓋,所以,內部類是不會像方法一樣被覆蓋,但是,如果手動繼承那就另說

關於內部類的詳細文章可以參考目錄 []

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4479/viewspace-2800542/,如需轉載,請註明出處,否則將追究法律責任。

相關文章