Javaのクラスにはフィールド変数やメソッドなどを定義するのが一般的ですが、インナークラス(内部クラス)と呼ばれる要素を定義することも可能です。
本記事では、インナークラスの概要から実際の使い方までをJava初心者の方向けにサンプルコードを掲載しながらご紹介していきます。
目次
Javaのインナークラスって何?
Javaではあるクラスの内部に別のクラスを定義することが可能です。
内部に定義されたクラスのことを「インナークラス(内部クラス)」と呼びます。
インナークラスの種類
インナークラスは更にいくつかの種類に分けられます。
- メンバークラス
- ローカルクラス
- 匿名クラス
メンバークラス
クラス内部にフィールド変数やメソッドなどと同じように定義したインナークラスの中で、非staticとして定義したクラスのことを「メンバークラス」と呼びます。
メンバークラスでは、外部クラスのフィールド変数にアクセス可能です。
メンバークラスを生成するには外部クラスをインスタンス化しておく必要があります。
ローカルクラス
メソッド内に定義するインナークラスのことを「ローカルクラス」と呼びます。
ローカルクラスでは、外部クラスのフィールド変数にアクセス可能ですが、メソッド内に定義された変数はfinalが付与されたもの以外アクセス出来ません。(Java1.7以前)
匿名クラス
クラスの名前を付けずに、宣言と実行を同時に行う1回限りのクラスを「匿名クラス」と呼びます。
コンストラクタが不要なシンプルで一度しか利用しないような処理で記述されます。
メンバークラスのJavaサンプルコード
メンバークラスは、フィールド変数やメソッドと同様に外部クラスのブロック内に記述します。
記述方法
class 外部クラス { フィールド変数; メソッド; 内部クラス { } }
内部クラスをインスタンス化するためには、外部クラスをインスタンス化しておく必要があります。
外部クラス 外部インスタンス = new 外部クラス(); 外部インスタンス.内部クラス 内部インスタンス =外部インスタンス.new 内部クラス();
サンプル
実際に内部クラスを利用すると下記のような記述となります。
public class Main { public static void main(String[] args) { Sample1 sample1 = new Sample1(); Sample1.Sample2 sample2 = sample1.new Sample2(); System.out.println(sample2.str2); sample2.innerExe(); // System.out.println(sample2.str1); これは実行出来ない // sample2.outerExe(); これも実行出来ない } } class Sample1 { String str1 = "外部クラスのフィールドです。"; public void outerExe() { System.out.println("外部クラスのメソッドを実行しました。"); } class Sample2 { String str2 = "内部クラスのフィールドです。"; public void innerExe() { System.out.println("内部クラスのメソッドを実行しました。"); System.out.println(str1); outerExe(); } } }
実行結果が下記です。
内部クラスのフィールドです。 内部クラスのメソッドを実行しました。 外部クラスのフィールドです。 外部クラスのメソッドを実行しました。
5行目が内部クラスをインスタンス化している部分です。
4行目で外部クラスをインスタンス化した上で、内部クラスのインスタンス化を実施しています。
内部クラスの処理として外部クラスのフィールド変数やメソッドを利用することは可能ですが、インスタンス化したオブジェクトから直接外部クラスにアクセス出来るわけではないため注意しましょう。
ローカルクラスのJavaサンプルコード
ローカルクラスは、外部クラスに定義されたメソッドの内側に記述します。
記述方法
class 外部クラス { フィールド変数; メソッド { ローカルクラス { } } }
サンプル
public class Main { public static void main(String[] args) { Sample1 sample1 = new Sample1(); sample1.outerExe(); } } class Sample1 { String str1 = "外部クラスのフィールドです。"; public void outerExe() { System.out.println("外部クラスのメソッドを実行しました。"); class Sample2 { String str2 = "内部クラスのフィールドです。"; public void innerExe() { System.out.println("内部クラスのメソッドを実行しました。"); System.out.println(str1); } } Sample2 sample2 = new Sample2(); sample2.innerExe(); System.out.println(sample2.str2); // System.out.println(sample2.str1); これは実行出来ない } }
実行結果が下記です。
外部クラスのメソッドを実行しました。 内部クラスのメソッドを実行しました。 外部クラスのフィールドです。 内部クラスのフィールドです。
ローカルクラスを利用することで、使用可能な範囲を明確化することは出来ますが、実際にはそれほど使われるものではありません。
明確な目的などがあれば利用すべきですが、理由もなく乱用することは避けましょう。
匿名クラスのJavaサンプルコード
匿名クラスは、クラスに名前を付けずにインスタンスを生成して利用します。
記述方法
class 外部クラス { 抽象クラス名 インスタンス名 = new 抽象クラス名 { 匿名クラス }; }
または
class 外部クラス { インターフェース名 インスタンス名 = new インターフェース名 { 匿名クラス }; }
サンプル
抽象クラスとインターフェースのメソッドをそれぞれ匿名クラスから利用してみます。
public class Main { public static void main(String[] args) { Sample1 sample1 = new Sample1() { public void execute() { System.out.println("匿名クラスで抽象クラスのメソッドを実行"); } }; sample1.execute(); Sample2 sample2 = new Sample2() { public void execute() { System.out.println("匿名クラスでインターフェースのメソッドを実装"); } }; sample2.execute(); } } abstract class Sample1 { abstract void execute(); } interface Sample2 { void execute(); }
実行結果が下記です。
匿名クラスで抽象クラスのメソッドを実行 匿名クラスでインターフェースのメソッドを実装
このように本来であれば抽象クラスやインターフェースを継承したクラスを別途作成しインスタンス化して利用しますが、匿名クラスを利用することで定義とインスタンス化を同時に実行しています。
さいごに: インナークラスを使いこなしてJavaプログラムを最適化しよう
本記事では、Javaにおけるインナークラスの概要と使い方についてサンプルコードを掲載しながらご紹介してきました。
インナークラスを使用することで、アクセス範囲が明確になり、公開したくない処理を隠蔽するために有効です。
初心者のうちはインナークラスの使い所が難しいのも事実ですが、適材適所でインナークラスを利用しJavaプログラムを最適化出来るようチャレンジしてみてください。
Java1.8以降はfinalが付与されていなくてもアクセス出来るようになっています。