一文讀懂JAVA內部類

一個簡單的內部類

public class OuterClazz {

    class InnerClazz{//inner class
        
    }
}

爲什麼要使用內部類

  • 提供一種方法把只在一個地方用的類邏輯分組
  • 增強封裝(可以理解一種類似“多重繼承”)
  • 容易維護

爲什麼說內部類可以實現類似的多重繼承,Java是不需要class多重繼承的,

想要實現類似多重繼承的效果可以用內部類,比如Class B 已經繼承了Class C 就沒有辦法繼承Class A,

但是把B設計成A的內部類,就可以訪問A的內部變量和方法了,就像是也繼承了A。

public class ClazzA {

    private int age = 0;
    public void printFromA(){
        System.out.println("The age in ClazzA is "+age);
    }
    //ClazzB 可以直接調用ClazzA的方法和訪問它的變量,
    class ClazzB extends ClazzC{//inner class
        public void print() {
            age++;
            printFromA();
        }
    }
    public static void main(String[] args) {
        ClazzB clazzB = new ClazzA().new ClazzB();
        clazzB.print();
    }
}

class ClazzC{
    
}

執行結果:

The age in ClazzA is 1

幾種內部類

  1. 靜態內部類
  2. 成員內部類
  3. 方法內部類(局部內部類)
  4. 匿名內部類

靜態內部類

靜態內部類是定義在另一個類裏面用 static 修飾 class 的類,靜態內部類不需要依賴於外部類(與類的靜態成員屬性類似)且無法使用其外部類的非 static 屬性或方法(因爲在沒有外部類對象的情況下可以直接創建靜態內部類的對象,如果允許訪問外部類的非 static 屬性或者方法就會產生矛盾)。

如果想訪問外部類的變量和方法只能通過外部類的實例。

public class OuterClazz {

    private int age = 0;
    private static int intAge = 10;
    public void printAge(){
        System.out.println("The age in ClazzA is "+age);
    }
    
    //ClazzB 可以直接調用ClazzA的方法和訪問它的變量,
    static class ClazzB {//inner class
        public void print() {
            System.out.println("The int age in Out class is "+intAge);
            OuterClazz outerClazz = new OuterClazz();
            outerClazz.age++;
            outerClazz.printAge();
        }
    }
    public static void main(String[] args) {
        ClazzB clazzB =  new OuterClazz.  ClazzB();
        clazzB.print();
    }
}

執行結果:

The int age in Out class is 10
The age in ClazzA is 1

成員內部類

成員內部類是沒有用 static 修飾且定義在在外部類類體中的類,是最普通的內部類,可以看做是外部類的成員,可以無條件訪問外部類的所有成員屬性和成員方法(包括 private 成員和靜態成員),而外部類無法直接訪問成員內部類的成員和屬性,要想訪問必須得先創建一個成員內部類的對象然後通過指向這個對象的引用來訪問;當成員內部類擁有和外部類同名的成員變量或者方法時會發生隱藏現象(即默認情況下訪問的是成員內部類的成員,如果要訪問外部類的同名成員需要通過 OutClass.this.XXX 形式訪問);成員內部類的 class 前面可以有 private 等修飾符存在。

public class OuterClazz {

    private int age = 0;
    private static int intAge = 10;
    public void printAge(){
        System.out.println("The age in ClazzA is "+age);
    }
    
    //ClazzB 可以直接調用ClazzA的方法和訪問它的變量,
     class ClazzB {//inner class
        public void print() {
            System.out.println("The int age in Out class is "+intAge);
            age++;
            printAge();
        }
    }
    public static void main(String[] args) {
        ClazzB clazzB =  new OuterClazz(). new  ClazzB();
        clazzB.print();
    }
}

執行結果和靜態內部類相同。

方法內部類

方法內部類(局部內部類)是定義在一個方法裏面的類,和成員內部類的區別在於方法內部類的訪問僅限於方法內;方法內部類就像是方法裏面的一個局部變量一樣,所以其類 class 前面是不能有 public、protected、private、static 修飾符的,也不可以在此方法外對其實例化使用。

public class LocalClazz {

    public static void testLocalClazz() {
        int age =10;
        class InnerClazz {
            public void pringAge() {
                //age++; //Error: Local variable age defined in an enclosing scope must be final or effectively final
                System.out.println("this age is "+age);
            }
        }
        InnerClazz innerClazz = new InnerClazz();
        innerClazz.pringAge();
    }

    public static void main(String[] args) {
        testLocalClazz();
    }
}

匿名內部類

匿名內部類是一種沒有構造器的類(實質是繼承類或實現接口的子類匿名對象),由於沒有構造器所以匿名內部類的使用範圍非常有限,大部分匿名內部類用於接口回調,匿名內部類在編譯的時候由系統自動起名爲 OutClass$1.class,一般匿名內部類用於繼承其他類或實現接口且不需要增加額外方法的場景(只是對繼承方法的實現或是重寫);匿名內部類的 class 前面不能有 pravite 等修飾符和 static 修飾符;匿名內部類訪問外部類的成員屬性時外部類的成員屬性需要添加 final 修飾(1.8 開始可以不用)。

public class AnonymousInnerClazz {
    private Animal animal = new Animal() {
        
        @Override
        public void eat() {
            System.out.println("eat, eat, eat!");
            
        }
    };
    public static void main(String[] args) {
        new AnonymousInnerClazz().animal.eat();
    }
    

}
interface Animal{
    public void eat();
}

執行結果:

eat, eat, eat!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章