#1. ネストクラスとは
クラス定義の中にさらにクラスを定義でき、その名称がネストクラスという。
##1-1. 特徴
シンプルで可読性に優れており、使用場所も限定されるため、その存在を外部から隠したいクラスに適用することが一般的。
##1-2. ネストクラスの種類
ネストクラスは以下の種類に分けられる。
##1-3. ネストクラスのルール
static/非static共通 | ・外側のクラスと同じクラス名は使用できない ・アクセス修飾子を使用できる。 ・abstract/final 修飾子を使用できる。 |
---|---|
staticクラスのみ | ・非static/static メンバをもつことができる ・外側のクラスで定義したインスタンス変数にアクセスできない |
非staticクラスのみ | ・staticメンバをもつことができない ・ 外側のクラスで定義したインスタンス変数にアクセスできる。 |
##1-4. ネストクラスのコンパイル
※アウタークラス = 外側のクラス
ネストクラスを定義したアウタークラスをコンパイルすると、アウタークラスのclassファイルと、ネストクラスのclassファイルが生成される。
生成されたネストクラスのファイル名は以下のようになる。
アウタークラス名$ネストクラス名.class
##1-5. ネストクラスへのアクセス
ネストクラス内のメンバはネストクラスをインスタンス化することで利用できる。
次の手法でインスタンス化が可能。
①外部クラスでネストクラスをインスタンス化する
②アウタークラスのメソッド内でネストクラスをインスタンス化する
###1-5-1. 外部クラスでネストクラスをインスタンス化
【構文】
・インナークラス(非staticクラス)の場合
/***アウタークラス名.インナークラス名 変数名 =
** new アウタークラス名().new インナークラス名();
*/
Outer.Inner obj = new Outer().new Inner();
・staticクラスの場合
/***アウタークラス名.staticクラス名 変数名 =
** new アウタークラス名.staticクラス名();
*/
Outer.StaticInner obj = new Outer.StaticInner();
###1-5-2. アウタークラスのメソッド内でネストクラスをインスタンス化
アウタークラスのmainメソッド内でネストクラスをインスタンス化し、ネストクラスで定義したメンバを呼び出す例。
class Outer{
private int id = 100;
class Inner { //staticメソッドは定義不可
public int id = 200;
//static void hogehoge(){...} //コンパイルエラー
void method(int id){
System.out.println("Local_scope_id" + id);
System.out.println("Inner_scope_id" + this.id);
System.out.println("Outer_scope_id" + Outer.this.id);
}
}
static class Staticinner { //外側のインスタンスメンバにはアクセス不可
public static int id = 300;
static void method(int id){
System.out.println(id);
System.out.println(Staticinner.id);
//System.out.println(Outer.this.id); //コンパイルエラー
}
}
public static void main(String... args){
//インナークラスのインスタンス化と呼び出し
new Outer().new Inner().method(400);
//new Inner().mehod(400); //コンパイルエラー
System.out.println();
//staticクラスのインスタンス化と呼び出し
new Outer.Staticinner().method(500); //基本構文
new Staticinner().method(600); //アウタークラス名省略可
Outer.Staticinner.method(700); //new省略可
Staticinner.method(800); //new,アウタークラス名省略可
}
}
※外側のクラスのインスタンスメンバにアクセスするには、「アウタークラス名.this.メンバ名」のようにthisの前に外側のクラス名を宣言する必要がある。
##1-6. インターフェースや抽象クラスでのネスト + その他
ネストクラスでは、インターフェースや抽象クラスの定義も可能
class Sample{
//継承したり
abstract class A {abstract void foo();}
class B extends A {void foo(){}}
//実装もOK
interface X {void hoge();}
class Y implements X {public void hoge(){}}
/*上記それぞれstatic付与可能。
ただし、インナーabstractクラスをstaticクラスで継承するとコンパイルエラーになる。(インナーインターフェースをstaticクラスで実装するのは問題なし)
勿論、static → staticもOK。
*/
}
また、インターフェースや抽象クラス内でもネストクラスを定義できる。
ネストクラスのネストクラスも定義可能...
#2. ローカルクラス
あるクラスのメソッド内に定義したクラスのこと。
##2-1. 特徴
・メソッド内でのみ有効(ローカル扱い)。
・ローカル扱いなので、アクセス修飾子やstaticは使用できない。
(つまり、非staticクラスのみ定義可)
##2-2. ローカルクラスのルール
ローカルクラス | ・アクセス修飾子(public,protected,private)は使用できない ・static修飾子は使用できない ・abstract修飾子、final修飾子を使用できる。 ・外側のクラスのメンバにアクセスできる。 ・ローカルクラスから外側のクラスのメソッドの引数およびローカル変数にアクセスするには、各変数がfinal(定数)でなければならない。したがって、SE7までは明示的にfinal修飾子の付与が必要であったが、SE8からは、暗黙的にfinalが付与されるようになったので、明示的な付与は不要。(つまり、事実上finalな変数といったところ) |
---|
##2-2. ローカルクラスのサンプルコード
//実質的finalとなるのはローカル変数のみ
class Outer{
private static int a = 1; //static変数
private int b = 2; //インスタンス変数
void methodOuter(int c, final int d){
final int e = 5; int f = 6;
class Local{
void methodLocal() {
System.out.println(a + "" + b + c + d + e + f);
//c = 100; コンパイルエラー
//d = 200; コンパイルエラー
}
}
a = 10; //OK
b = 20; //OK
//e = 300; コンパイルエラー
//f = 400; コンパイルエラー
new Local().methodLocal();
}
public static void main(String... args){
Outer obj = new Outer();
obj.methodOuter(3, 4);
}
}
//実行結果
10203456
#3. 匿名クラス
クラス名を指定せずに、クラス定義とインスタンス化を1つの式として記述したクラスのこと
##3-1. 特徴
・実態は、あるクラスのサブクラスまたは、あるインターフェースを実装したクラスであり、「new スーパークラス」or「new インターフェース」の後にオーバーライドする処理(メソッド)をブロック内に記述する。
・匿名クラスは1つの式として定義するため最後にセミコロンが必要。
・再利用する必要がなく、特定の場所のみで実装したい場合に使用する。したがって、クラス名を宣言せずにクラス定義とインスタンス化を同時に行う。
・関数型インターフェースで活用できるが、記述が容易なラムダ式が主流
##3-2. 匿名クラスのルール
匿名クラス | ・アクセス修飾子(public,protected,private)を使用できない ・static修飾子をしようできない ・abstract修飾子、final修飾子を使用できない ・外側のクラスのメンバにアクセスできる ・ 外側のクラスのメソッドの引数及びローカル変数にアクセスできる(但し、暗黙的final) ・コンストラクタを定義できない |
---|
##3-3. 匿名クラスの定義例
・オブジェクト格納なし
class Sample1{
private String name1 = "piyoko"; //再代入可
void method(String name2){ //再代入不可
new MyInter(){
public void piyo(){
System.out.println(name1 + " & " + name2);
}
}.piyo();
}
public static void main(String... args){
new Sample1().method("piyota");
}
}
interface MyInter{
void piyo();
}
・オブジェクト格納あり
class Sample2{
public static void main(String... args){
MyInter obj = new MyInter() {
public void hoge(String name) {
System.out.println(name);
}
};
obj.hoge("hogeta");
}
}
interface MyInter{
void hoge(String name);
}
//ラムダ式の場合
MyInter obj = (name) -> {System.out.println(name);}; //中括弧で括った時のセミコロン付け忘れに注意
MyInter obj = name -> System.out.println(name);
//メソッド参照
MyInter obj = System.out::println;
#参考文献
・オラクル認定資格教科書 Javaプログラマ Gold SE 8 (EXAMPRESS)
おわり