Java內部類

Acelin_H發表於2021-07-19

內部類簡介


Java 一個類中可以巢狀另外一個類,語法格式如下:

class OuterClass {   // 外部類
    // ...
    class NestedClass { // 巢狀類,或稱為內部類
        // ...
    }
}

巢狀類有如下幾種型別:

image


成員內部類


最簡單的一種內部類,形式如下,跟其他變數一樣,是一個類中的一個成員

class Outer {
    
    String str = "hello";
     
    public Outer(String str) {
        this.str = str;
    }
    
    /* 內部類 */
    class Inner {     
        public void showStr() {
            System.out.println(str);
        }
    }
}

  • 成員內部類可以無條件地訪問外部類的所有元素
  • 外部類訪問內部類需要先建立一個內部類物件
  • 成員內部類是依附外部類而存在
可以訪問外部類原理

編譯器會在編譯時生成外部類和內部類兩個位元組碼檔案,還會給內部類的無參建構函式增加一個引數,為外部類的一個應用,且指向了外部類,故可以隨意使用外部類一切。

側面說明成員內部類依賴於外部類的優先建立,不然會初始化失敗


區域性內部類


定義在一個方法或者一個作用域裡面的類,區域性內部類的訪問僅限於方法內或者該作用域內

class MyClass{
    public MyClass() {
         
    }
}
 
class Outer{
    public Outer(){
         
    }
     
    public MyClass getInner{
        
        /* 區域性內部類 */
        class Inner extends MyClass{   
            int age = 0;
        }
        return new Inner();
    }
}

區域性內部類就像是方法裡面的一個區域性變數一樣,是不能有 public、protected、private 以及 static 修飾符的


匿名內部類


先看一下官方給的例子

public class HelloWorldAnonymousClasses {

    /**
     * 包含兩個方法的HelloWorld介面
     */
    interface HelloWorld {
        public void greet();
        public void greetSomeone(String someone);
    }

    public void sayHello() {

        // 1、區域性類EnglishGreeting實現了HelloWorld介面
        class EnglishGreeting implements HelloWorld {
            String name = "world";
            public void greet() {
                greetSomeone("world");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Hello " + name);
            }
        }

        HelloWorld englishGreeting = new EnglishGreeting();

        // 2、匿名類實現HelloWorld介面
        HelloWorld frenchGreeting = new HelloWorld() {
            String name = "tout le monde";
            public void greet() {
                greetSomeone("tout le monde");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Salut " + name);
            }
        };

        // 3、匿名類實現HelloWorld介面
        HelloWorld spanishGreeting = new HelloWorld() {
            String name = "mundo";
            public void greet() {
                greetSomeone("mundo");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Hola, " + name);
            }
        };

        englishGreeting.greet();
        frenchGreeting.greetSomeone("Fred");
        spanishGreeting.greet();
    }

    public static void main(String... args) {
        HelloWorldAnonymousClasses myApp = new HelloWorldAnonymousClasses();
        myApp.sayHello();
    }
}

匿名類表示式包含以下內部分:

  1. 操作符:new;
  2. 一個要實現的介面或要繼承的類,案例一中的匿名類實現了HellowWorld介面,案例二中的匿名內部類繼承了Animal父類;
  3. 一對括號,如果是匿名子類,與例項化普通類的語法類似,如果有構造引數,要帶上構造引數;如果是實現一個介面,只需要一對空括號即可;
  4. 一段被"{}"括起來類宣告主體;
  5. 末尾的";"號(因為匿名類的宣告是一個表示式,是語句的一部分,因此要以分號結尾)。

本部分參考JAVA匿名內部類(Anonymous Classes)


靜態內部類


靜態內部類是不需要依賴於外部類的,並且它不能使用外部類的非static成員變數或者方法,這個和普通靜態方法不能訪問非靜態方法或變數的原理一樣,具體可以瞭解一下類的載入生命週期。

簡單地說就是靜態變數或方法是屬於類的,非靜態方法或變數是屬於物件的,jvm載入類的時候就為類的靜態變數或方法分配記憶體的,而非靜態的需要等到要初始化物件時候才給分配記憶體,而這個過程是動態的,也就是等到我們什麼時候想用,才會有累的初始化過程。

簡單舉個例子:

 
class Outer {
	int a = 1
	static int a = 2;
    public Outter() {
         
    }
     
	/* 靜態內部類 */
    static class Inner {
        public Inner() {
             System.out.println(a); // 編譯會報錯
             System.out.println(b);

        }
    }
}

使用:

public class Test {
    public static void main(String[] args)  {
        Outer.Inner inner = new Outer.Inner();
    }
}

內部類簡單應用


為什麼在 Java 中需要內部類?總結一下主要有以下四點內部類的使用場景和好處:

  • 1.每個內部類都能獨立的繼承一個介面的實現,所以無論外部類是否已經繼承了某個(介面的)實現,對於內部類都沒有影響。內部類使得多繼承的解決方案變得完整。
  • 2.方便將存在一定邏輯關係的類組織在一起,又可以對外界隱藏。
  • 3.方便編寫事件驅動程式。
  • 4.方便編寫執行緒程式碼。

相關文章