インスタンスイニシャライザ?
構文
文で説明するよりコードを見たほうが早いです。
public class Book {
private final List<Author> authors;
private final String title;
// etc...
// インスタンスイニシャライザ
{
authors = new ArrayList<Author>();
}
public Book(String title) {
this.title = title;
}
// 以下略
}
クラスブロックの直下に書かれた、無名のブロックが今回話題にしているインスタンスイニシャライザです。static イニシャライザの static がない版ですね。
呼ばれるタイミング
低レベルなところまでは調べてないのですが、コンストラクタとどっちが先に呼ばれているのか、調べてみました。愚直に System.out.println してるだけです。
public class Hoge {
static {
System.out.println("static イニシャライザ");
}
{
System.out.println("インスタンスイニシャライザ");
}
public Hoge() {
System.out.println("コンストラクタ");
}
public Hoge(String param) {
this();
System.out.println("引数有りコンストラクタ");
}
public static void main(String[] args) {
new Hoge();
new Hoge("hogehoge");
}
}
結果は以下のように。
static イニシャライザ インスタンスイニシャライザ コンストラクタ インスタンスイニシャライザ コンストラクタ 引数有りコンストラクタ
コンストラクタが呼び出されるより前に呼ばれるみたいです。
使い道
ここまで引っ張っておいてなんですが、ほとんど使い道が見当たりません。
共通化できないコンストラクタ間で、パラメータなしに同じことを実行したい。ただし一度しか行いたくないので、メソッドにはしたくない、という場合ぐらいでしょうか。
あんまりいい例が思いつかないんですが、どのコンストラクタを呼ばれても、必ずリストの先頭にダミーを挿入しなければならないということをする場合を考えてみます。
インスタンスイニシャライザを使わなければ、以下のようにするのが普通でしょう。
public class Fuga {
private List<Object> list = new ArrayList<Object>();
public Fuga(int n) {
list.add(new Dummy());
}
public Fuga(String s) {
list.add(new Dummy());
}
}
インスタンスイニシャライザを使えば次のようになります。
public class Fuga {
private List<Object> list = new ArrayList<Object>();
{
list.add(new Dummy());
}
public Fuga(int n) {
}
public Fuga(String s) {
}
}
Arrays.asList を使えるじゃんとかツッコミたくなるかもしれません。無理やり作った例なので勘弁してください。
こういうことをしなければならない状況がどれほどあるかは定かではありません。少なくとも数多くこのイディオムを使うことはなさそうです。
結論
正直なところ、今回のインスタンスイニシャライザについてはどうでもよかったりします。ただ、Java にはこういった構文の抜け道みたいなのが結構あります。static イニシャライザも元々は想定されてなかったが、ユーザによって発見されて普及したという話を、どこかで見たような気がします。ソースを失念したので定かではありませんが。
他にもジェネリクスの周りなどは、構文の抜け道が結構あります。今回のインスタンスイニシャライザはあまり役に立つことがなさそうなトピックでしたが、ジェネリクス周りは煩雑な部分をスッキリさせるものもあったりします。
ちなみに今回のインスタンスイニシャライザは、static イニシャライザにするべきところの static が抜けているコードを見て、発見しました。要はバグです。問題がなかったのか心配です。
Re: インスタンスイニシャライザ?
カタカナ表記するならインスタンスイニシャライザで正解だと思います。言語仕様上は InstanceInitializerの様ですし。(確認してみたところ第2版から追加されているようです。)
導入主目的はおそらく匿名内部クラスの初期化のためでしょう(ほんとのところは知りません)。コンストラクタかけない状況では使用するメリットが有るかもと。
以下 The Java Language Specification, Third Edition 8.1.6 Class Body and Member Declarations より。
ClassBody:
{ ClassBodyDeclarations<sub>opt</sub> }
ClassBodyDeclarations:
ClassBodyDeclaration
ClassBodyDeclarations ClassBodyDeclaration
ClassBodyDeclaration:
ClassMemberDeclaration
InstanceInitializer
StaticInitializer
ConstructorDeclaration
ClassMemberDeclaration:
FieldDeclaration
MethodDeclaration
ClassDeclaration
InterfaceDeclaration
;