ネストクラス・インナークラスに関して勉強中ですが、
下記のようなルール
(1)非staticなネストクラスは、staticなメンバ・フィールドを持てない
(2)非staticなネストクラスのオブジェクトは、外側のオブジェクトを
生成してから生成する
(3)staticなネストクラスは、自分を含むクラスに付随し、外側の
オブジェクトがなくとも使える
(4)staticなメソッド内で、非staticなネストクラスのオブジェクトは
生成できない
(5)メソッド内で定義されたインナークラスからアクセスできるのは
*外側のメソッドのIfinalなI引数・変数
*メソッドを持つクラスのフィールド
などあるようですが、そういうものかと頭では思えても、
・なぜそのようなルールがあるのか、
・このような仕組みは、実際の開発ではどのように
使われているのか、
といったことが見えてこないので、IぴんとIきません。
そこで、このネストクラス・インナークラスの仕組みがよく
分かるようになるサイト等をご存知の方がおりましたら
ご教授下さいますようお願いします。
http://www.kab-studio.biz/Programing/JavaA2Z/Word/00000889.html
JavaA2Z【内部クラスとは】
どーも、自分もJavaについて勉強中ですが、確かにピンとこないですよね。このネストクラス&インナークラスも、結構やっかいです。とりあえず、参考URLを貼り付けておきます。
> なぜそのようなルールがあるのか、
(1) 非staticなインナークラスは、外側のクラスの*インスタンス*に属します。要するに、外側のクラスのインスタンス変数のような扱いです。しそのようなクラスがstaticなメンバを持つなら、それは外側のクラスから見ると、インスタンス変数且つstaticとなってしまい、メンバのスコープがあいまいになります。そのため禁止されています。
(2) javap -c -private ’CLASS$InnerClass’ を実行すると分かりますが、非staticなinnerクラスは暗黙のうちに外側のクラスのインスタンスをコンストラクタの引数に取り、それがinnerクラスのfinalなメンバとしてフィールドに置かれるためです。
(3)クラスのFQCNに外側のクラス名が入りますが、それ以外は普通のクラスと同じだからです。
(4) (2)に関連しますが、staticなメソッドは非staticなネストクラスのコンストラクタの暗黙引数である外側クラスのインスタンス”this”を渡せないからです。
(5) finalでない引数、変数は、インナークラス作成後に、外側クラスやメソッドによって参照先アドレスが変更される可能性があります。それに対応できないためです。
例えば、
str = ”This is string”;
a = new MyClass(){
void run(){
System.out.println(str);
}
};
str=”This is another string”;
a.run()
のようなコードが書けたとして、表示されるのは ”This is string”の方になります。間違いを犯し易いので禁止されているのだと思います。
http://www.javaworld.com/javaworld/javatips/jw-javatip106.html
Java Tip 106: Static inner classes for fun and profit
・このような仕組みは、実際の開発ではどのように使われているのか
まず、非static、且つ匿名でないインナークラスが使われている所をSunの認定試験以外で私は見たことがないです。
つまり、実戦的にはあまり必要ない知識だと思います。
staticなインナークラスと、匿名インナークラス(メソッド内インナークラス)はよく使われます。
staticなインナークラスは外側クラスのprivateなstatic変数にもアクセスできるので、テストでも使えますし、パラメータを大量に渡さないとダメな場合にも重宝します。
また普通のクラスのように扱えるので、例えば匿名インナークラスだと何箇所にも同じような定義をしなければならなくなるような場合にも使えます。
一方匿名インナークラスは、「型」として特定のものがいるけど、クラスとして定義する程ではないような物に使います。よくあるのが、
new Thread(){ public void run(){ doSomething();}}.start()
のように、あるメソッドだけを別スレッドで実行する場合とか、
file.list(new FileFilter(){ public boolean accept(File f){
return f.toString().endsWith(”.java”);
}});
のように、どうしても別の型を使わないとダメだけど、独立してクラスを定義する程ではない場合です。他の言語でいうと、ラムダ式やクロージャの代わりといった感じです。
ありがとうございます。
拝見させていただくのが遅くなってしまい、
申し訳ありません。
質問させていただいて、現時点でじっくり
熟読できず、申し訳ございません。
参照させていただきます。
ありがとうございます。
拝見させていただくのが遅くなってしまい
申し訳ありません。
取り急ぎ、参考文献の1つにさせていただきます。