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
    }
  }
}