HOWTO · Java
Java の内部クラスと静的ネストクラス
コンピュータープログラミングでは、クラスは、データメンバーまたはメンバー関数のいずれかからデータにアクセスするための個々のクラスオブジェクトを作成できるようにする青写真です。Java プログラミングでは、クラスはキーワード class で定義されます。クラスは、カスタム変更を加えたユーザー定義のデータタイプであるとも言えます。
このページの内容
ネストクラスは、別のクラスの内部で宣言されるクラスです。Java には static ネストクラスと、static ではないネストクラス(内部クラス)があります。型が概念上は外側のクラスに属していても、外側のオブジェクトを必要としない場合は、static ネストクラスを使います。static キーワードはその関係を示すもので、ネストされた型をトップレベルクラスにしたり、セキュリティ境界を設けたりするものではありません。
Java の static ネストクラス
static ネストクラスは、別のクラスの内部で static キーワードを付けて宣言するメンバー型です。たとえば Envelope.Label のように外側の型名を付けて参照でき、Envelope オブジェクトを先に作らなくてもインスタンス化できます。外側のクラスと密接に関係していて、独立したトップレベル型にする意味がないヘルパー型や値型に適しています。
ネストされた型にも独自のインスタンスがあります。クラスに static を付けても、そのフィールドやメソッドが static になるわけではありません。トップレベルクラスと同じように、独自のコンストラクター、インスタンス状態、メソッドを持たせることができます。
static ネストクラスと外側のクラスとの関係
static ネストクラスは、外側のクラスのインスタンスへの暗黙の参照を持ちません。外側のクラスの static メンバーには、private の static メンバーも含めて直接アクセスできます。一方、対応する外側のオブジェクトがないため、外側のインスタンスフィールドやメソッドは直接使えません。そのデータが必要なら、外側のオブジェクトをコンストラクターまたはメソッドに渡し、その参照を通じてメンバーにアクセスします。
逆方向のアクセス関係も役立ちます。外側のクラスのコードは、Java の通常のアクセス規則に従って、ネストされたクラスの private メンバーを含むメンバーを扱えます。private はメンバーを参照できるコードを制限するものであり、セキュリティ機能として説明するべきではありません。
static ネストクラスを宣言してインスタンス化する
外側のクラス本体で static class Label のように型を宣言します。外側のクラスの外部からは Envelope.Label として参照します。次の完全な例では、ネストされた値型をそれを使うクラスとまとめ、main から直接生成します。
この例を実行してください。出力には「Label: priority」と表示されます。コードと出力のバイト単位の一致を保つため、このラベルは英語のままです。
public class Main {
static class Label {
private final String text;
Label(String text) {
this.text = text;
}
String display() {
return "Label: " + text;
}
}
public static void main(String[] args) {
Label label = new Label("priority");
System.out.println(label.display());
}
}
Label: priority
main は static メソッドなので、Main を生成せずに Label を作成します。別のクラスからは修飾名 Main.Label を使い、アクセス可能なコンストラクターを呼び出せます。ネストされたクラスが特定の外側オブジェクトの情報を必要とする場合は、そのオブジェクトを渡して依存関係を明示します。
static ネストクラスと内部クラスの違い
内部クラスは static ではないメンバークラスです。各内部クラスオブジェクトは外側のクラスのインスタンスと結び付いており、そのコードから外側のインスタンスのメンバーを直接参照できます。外側のクラスの外部で内部クラスを作るには、まず外側のオブジェクトを生成し、次に outer.new Inner() の形式を使います。内部型の名前は Outer.Inner です。
static ネストクラスにはそのような結び付きがないため、生成時に外側のオブジェクトは使いません。外部からは new Outer.Nested() を使い、スコープ内では短い型名を使えます。どちらの形式も、API の意図に応じて private または public にでき、外側のクラスの private メンバーにもアクセスできます。違いは暗黙の外側インスタンスとの関係であり、セキュリティ上の特別な段階ではありません。
static ネストクラスを使う場面
ネストされた型が論理的に外側のクラスの一部でありながら、各インスタンスが外側のオブジェクトへの暗黙の参照なしに処理できる場合は、static ネストクラスを選びます。小さな値型、ビルダー、外側の API に固有の意味を持つヘルパーなどが適しています。static ネストクラスにも依存関係を明示的に渡せるため、呼び出し側から必要なものが分かります。
各インスタンスが、それを作成した特定の外側オブジェクトと連携する必要がある場合は、内部クラスを選びます。たとえば、そのオブジェクトのインスタンス状態を読み取ったり更新したりする場合です。型に幅広く独立した役割があるなら、トップレベルクラスのほうが再利用や発見が容易なことがあります。コードが必要とする関係に基づいて選び、用途を満たす範囲で最も狭い可視性を指定してください。