Java內部類


內部類是什麼?

作為包的成員的類被稱為頂級類。一個類可以在另一個類中宣告。 這種型別的類稱為內部類。
如果在另一個類中宣告的類被顯式或隱式宣告為static,它被稱為巢狀類,而不是內部類。
包含內部類的類稱為封閉類或外部類。

範例

下面的程式碼宣告一個內部類。

class Outer {
  public class Inner {
    // Members of the Inner class go here
  }
  // Other members of the Outer class go here 
}

Outer類是一個頂級類。Inner類是一個內部類。 它是外類的成員。Outer類是Inner類的封閉(外部)類。內部類可以是另一個內部類的封閉類。 內部類的巢狀層次沒有限制。

內部類的範例只能存在於其封閉類的範例中。

使用內部類的優點

以下是內部類的一些優點:

  • 在使用它們的其他類中定義類。
  • 提供了一個額外的名稱空間來管理類結構。
  • 一些設計模式使用內部類更容易實現。
  • 實現回撥機制使用內部類是優雅和方便的。它有助於在Java中實現閉包。

存取區域性變數的限制

下面的程式碼演示了存取區域性內部類中的區域性變數的規則。
main()方法宣告兩個區域性變數:xy。 這兩個變數都是被宣告為 final。變數x在被初始化之後不能改變,變數y也不能被改變,因為它被宣告為final

public class Main {
  public static void main(String... args) {
    final int x = 1;
    final int y = 2;

    class LocalInner {
      void print() {
        System.out.println("x = " + x);
        System.out.println("y = " + y);
      }
    }
    /*
     * Uncomment the following statement will make the variable x no longer
     * an effectively final variable and the LocalIneer class will not compile.
     */
    // x = 100;

    LocalInner li = new LocalInner();
    li.print();
  }
}

上面的程式碼生成以下結果。

x = 1
y = 2

內部類和繼承

內部類可以繼承另一個內部類,頂級類或其封閉類。

class A {
  public class B {
  }

  public class C extends B {
  }

  public class D extends A {
  }
}

class E extends A {
  public class F extends B {
  }
}

內部類中沒有靜態成員

Java中的關鍵字static使一個構造成為一個頂層結構。因此,不能為內部類宣告任何靜態成員(欄位,方法或初始化器)。
允許在內部類中有作為編譯時常數的靜態欄位。

class A {
  public class B {
    public final static int DAYS_IN_A_WEEK = 7; // OK
    public final String str = new String("Hello");
  }
}

生成的內部類的類檔案

每個內部類都被編譯成一個單獨的類檔案。成員內部類和靜態內部類的類檔案名格式如下:

<outer-class-name>$<member-or-static-inner-class-name>

本地內部類的類檔案名的格式如下:

<outer-class-name>$<a-number><local-inner-class-name>

匿名類的類檔案名的格式如下:

<outer-class-name>$<a-number>

類檔案名中的<a-number>是從1開始順序生成的數位,以避免任何名稱衝突。

靜態上下文中的內部類

可以在靜態上下文中定義一個內部類,例如靜態方法或靜態初始化器。所有靜態欄位成員都可以存取這樣的內部類。

class Outer {
  static int k = 1;
  int m = 2;

  public static void staticMethod() {
    // Class Inner is defined in a static context
    class Inner {
      int j = k; // OK. Referencing static field k
      // int n = m; // An error. Referencing non-static field m
    }
  }
}