【Java】内部クラス(インナークラス)の使い方(static class)

こんにちは!侍エンジニアインストラクターの本多です。

みなさんは、クラスの中にクラスを定義することが可能なのはご存知でしょうか?その名も内部クラス(インナークラス)といいます。この記事では、

内部クラスとは何なの?
内部クラスの使い方について知りたい

という基本的な疑問から、

  • static内部クラスとは何か
  • static内部クラスの使い方

といった応用的な内容に関しても解説していきます。今回は内部クラスについて、わかりやすく解説していきます!

内部クラス(インナークラス)とは

クラスのメンバーはと聞かれて思いつくのは、フィールド変数とメソッドです。その他にクラスもあるよ、と言われると「??」となりますよね。クラスの中にクラスを定義する、これを内部クラス(インナークラス)といいます。

内部クラスはクラスをメンバーと同じように扱うことができます。メンバーと同じようにprivate、protected、publicといったアクセスレベルを付与することができます。また、内部クラスからは同じクラス内のフィールド変数、メソッドを参照することができます。

ですので、あるクラス内のフィールド変数やメソッドにアクセスするクラスを宣言する場合に内部クラスとして宣言します。あるクラスのフィールド変数やメソッドに別のクラスからアクセスする方法としては、継承してサブクラスを宣言する方法があります。

でも、そこまでしたくないというときに内部クラスを宣言すると便利です。内部クラスはメソッド内でも宣言することもできます。その場合、メソッド内のみで機能します。

なお、内部クラスを持つクラスのことを外部クラスといいます。

内部クラスの使い方

内部クラスは一般的なクラスと同じようにインスタンスを生成して使用します。内部クラスのインスタンスを生成する記述は以下のようになります。

外部クラス名 外部クラスのオブジェクト名 = new 外部クラス名();
外部クラス名.内部クラス名 内部クラスのオブジェクト名 = 外部クラスのオブジェクト名.new 内部クラス名();

内部クラスのインスタンスを生成するには、まず外部クラスのインスタンスを生成します。次に外部クラスからドット演算子(「.」)を使ってメソッドと同じように内部クラスを呼び出し、内部クラスのオブジェクトを宣言します。

宣言した内部クラスのオブジェクトに外部クラスのオブジェクトから生成する内部クラスのインスタンスを格納します。サンプルコードで確認していきましょう。

// 外部クラス
class OuterClass {
    private String str = "OuterClassの変数";
    
    // 内部クラス
    class InnerClass {
        public void innerSample() {
            System.out.println(str);
        }
    }
}

public class Main {
 
    public static void main(String[] args) {
        // 外部クラスのインスタンスの生成
        OuterClass oc = new OuterClass();
        // 外部クラスのオブジェクトから内部クラスのインスタンスを生成
        OuterClass.InnerClass ic = oc.new InnerClass();
        ic.innerSample();
    }

}

実行結果:

OuterClassの変数

このサンプルプログラムでは、OuterClassの中に内部クラスInnerClassを宣言しています。InnerClassを使用するためにまず、OuterClassのインスタンスを生成しています。

次に外部クラスのオブジェクトocから内部クラスのインスタンスを生成し、内部クラスのオブジェクトicに格納しています。実行結果から、内部クラスから外部クラスにある変数にアクセスできていることがわかります。

あるクラスの変数に別のクラスからアクセスする方法として、継承してサブクラスを宣言する方法もあるのですが、そこまでしたくないというときに内部クラスを宣言すると便利です。

staticな内部クラスの使い方

内部クラスをstaticクラスで宣言する場合はどうなるでしょうか?その場合は以下のようにインスタンスを生成する記述を変える必要があります。

外部クラス名.内部クラス名 内部クラスのオブジェクト名 = new 外部クラス名.内部クラス名();

また、staticな内部クラスから外部クラスの非staticなメンバーにはアクセスできません。ですので、外部クラスのメンバーにアクセスする場合は、外部クラスのメンバーもstaticで宣言する必要があります。サンプルコードで確認していきましょう。

// 外部クラス
class OuterClass {
    // staticなフィールド
    private static String str = "OuterClassの変数";
    
    // staticな内部クラス
    static class InnerClass {
        public void innerSample() {
            System.out.println(str);
        }
    }
}

public class Main {
 
    public static void main(String[] args) {
        // staticな内部クラスのインスタンスを生成
        OuterClass.InnerClass ic = new OuterClass.InnerClass();
        ic.innerSample();
    }

}

実行結果:

OuterClassの変数

このサンプルプログラムでは、OuterClassの中に内部クラスInnerClassをstaticで宣言しています。InnerClassを使用するために、外部クラスから内部クラスを呼び出しインスタンスを生成し、内部クラスのオブジェクトicに格納しています。

staticな内部クラスから外部クラスのフィールド変数にアクセスするために、外部クラスのフィールド変数もstaticで宣言しています。実行結果から、staticな内部クラスから外部クラスにあるstaticなフィールド変数にアクセスできていることがわかります。

このようにstaticな内部クラスは外部クラスのstaticなメンバーにのみアクセス可能なので、外部クラスのメンバーとの関係性は比較的薄くなり、通常の別のクラスとして宣言した場合に近くなります。

staticな内部クラスの注意点

staticな内部クラスを非staticな内部クラスと同じようにインスタンス化したり、外部クラスの非sutaticなメンバーにアクセスしようとするとエラーが発生するので、注意してください。

インスタンス化の記述について

staticな内部クラスを非staticな内部クラスと同じようにインスタンス化すると、以下のサンプルコードのようにエラーが発生します。注意してください!

// 外部クラス
class OuterClass {
    // staticなフィールド
    private static String str = "OuterClassの変数";
    
    // staticな内部クラス
    static class InnerClass {
        public void innerSample() {
            System.out.println(str);
        }
    }
}

public class Main {
 
    public static void main(String[] args) {
        // 外部クラスのインスタンスの生成
        OuterClass oc = new OuterClass();
        // 外部クラスのオブジェクトから内部クラスのインスタンスを生成
        OuterClass.InnerClass ic = oc.new InnerClass();
        ic.innerSample();
    }

}

実行結果:

Main.java:20: error: qualified new of static class

内部クラスをstaticクラスで宣言すると、完全に別のクラスとして扱われるため、エラーになります。

非staticクラスへのアクセスについて

staticな内部クラスから外部クラスの非sutaticなメンバーにアクセスしようとすると、以下のサンプルコードのようにエラーが発生します。注意してください!

// 外部クラス
class OuterClass {
    // 非staticなフィールド
    private String str = "OuterClassの変数";
    
    // staticな内部クラス
    static class InnerClass {
        public void innerSample() {
            System.out.println(str);
        }
    }
}

public class Main {
 
    public static void main(String[] args) {
        // staticな内部クラスのインスタンスを生成
        OuterClass.InnerClass ic = new OuterClass.InnerClass();
        ic.innerSample();
    }

}

実行結果:

Main.java:9: error: non-static variable str cannot be referenced from a static context

内部クラスから外部クラスのフィールド変数、つまりstaticクラスから非staticクラスの変数へアクセスしようとしています。

Javaでは基本的にstaticからstaticでないもの(インスタンスのフィールド変数やメソッド等)にはアクセスできないという決まりがあります。

クラスについてもっと詳しく知りたい方へ

クラスのさまざまな使い方については、以下の記事にまとめていますので、ぜひ参考にしてくださいね!

【Java入門】クラスの使い方総まとめ
更新日 : 2019年7月24日

static修飾子の使い方総まとめ

static修飾子のいろいろな使い方を次の記事にまとめているので、ぜひ確認してください!

【Java入門】static修飾子の使い方総まとめ
更新日 : 2017年6月9日

まとめ

ここでは、内部クラスの扱い方や注意点を説明しました。継承するほどでもないし、かといって別にメソッドを定義するだけでは整理がつかない、といった場合、解決の1つとして内部クラスを使ってみてください。

そして、内部クラスの使い方を忘れた時は、本記事を参考にしてくださいね!

プログラミング学習を効率良く進めたいなら…

学習を始めたけどエラーが解決できない
作りたいものはあるけど、何から始めればいいかわからない
プログラミングに対して、このような悩みを持っている方も多いですよね。

そんな方には、弊社が運営するサブスク型のプログラミングスクール「SAMURAI ENGINEER Plus+がおすすめです。



月額2980円(税別)で、主に4つのサービスを提供させていただきます。

  • 現役エンジニアによる月1度の「マンツーマン指導」
  • 平均回答時間30分の「Q&Aサービス」
  • 作りながら学べる28種類の「教材」
  • 学習を記録&仲間と共有できる「学習ログ」

目的にあった教材を選べば、どなたでも効率よく学習できるほか、Q&Aサービスやマンツーマン指導を活用することで、挫折せずにプログラミングの習得が可能です。

プログラミングを効率的に学びたい人はもちろん、何から始めたらよいのかわからない方は、ぜひ「SAMURAI ENGINEER Plus+」をご利用ください。
まずは30日無料体験

書いた人

本多 農

関西在住のITエンジニアです。普通の会社に勤務しながら、侍エンジニアのインストラクター、ライターとして活動しています。