インスタンスイニシャライザ
インスタンスイニシャライザを指定すると、クラスのインスタンス生成時に特定の処理を行うことができます。
- クラスの直下( class Hoge { /*ここ*/ } )に「{<処理>;...}」の形式で書きます。
- スタティックイニシャライザと同じノリですね。
- 指定した処理は、オブジェクトを生成する時「コンストラクタの前」に実行されます。
- イニシャライザのブロック中では、「this」が利用でき、省略も可能です。
サンプル。
/**親クラス*/ private static class Animal { Animal() { System.out.println( "initialize animal." ); } // 親のインスタンスイニシャライザ { System.out.println( "instance initializer parent." ); } } /**派生クラス*/ private static class Kitten extends Animal { // インスタンスイニシャライザ1 { System.out.println( "instance initializer 1." ); } // インスタンスイニシャライザ2 { System.out.println( "instance initializer 2." ); } Kitten() { System.out.println( "initialize kitten." ); } } /** * メイン * @param args 引数 */ public static void main ( String[] args ) { new Kitten(); }
実行結果です。
instance initializer parent. initialize animal. instance initializer 1. instance initializer 2. initialize kitten.
使いどころ
次のようなメンドクサイクラスを使うはめになった時、これを使うとスマートに書けそう!と思いました。
まずは、インスタンスイニシャライザを使わない場合。
LocationConditionsDomain locationConditions = new LocationConditionsDomainImpl(); List<LocationConditionDomain> tmp = new ArrayList<LocationConditionDomain>(3); LocationConditionDomain locationCondition = new LocationConditionDomainImpl(); ObjectIdentityDomain objectIdentity = new ObjectIdentityDomainImpl(); objectIdentity.setId( "hoge" ); locationCondition.setObjectIdentity( objectIdentity ); tmp.add( locationCondition ); locationCondition = new LocationConditionDomainImpl(); objectIdentity = new ObjectIdentityDomainImpl(); objectIdentity.setId( "foo" ); locationCondition.setObjectIdentity( objectIdentity ); tmp.add( locationCondition ); locationCondition = new LocationConditionDomainImpl(); objectIdentity = new ObjectIdentityDomainImpl(); objectIdentity.setId( "var" ); locationCondition.setObjectIdentity( objectIdentity ); tmp.add( locationCondition ); locationConditions.setDepth( DepthDomain.INFINITY ); locationConditions.setList( tmp );
コンストラクタで引数を受け付ける設計になってないので、ちまちまsetしていかないといけません。メンドイ。
ここで、インスタンスイニシャライザを使うと次のように書けます!
LocationConditionsDomain locationConditions = new LocationConditionsDomainImpl() {{ setDepth( DepthDomain.INFINITY ); setList( new ArrayList<LocationConditionDomain>(3) {{ add( new LocationConditionDomainImpl() {{ setObjectIdentity( new ObjectIdentityDomainImpl() {{ setId("hoge"); }} ); }} ); add( new LocationConditionDomainImpl() {{ setObjectIdentity( new ObjectIdentityDomainImpl() {{ setId("foo"); }} ); }} ); add( new LocationConditionDomainImpl() {{ setObjectIdentity( new ObjectIdentityDomainImpl() {{ setId("var"); }} ); }} ); }}); }};
Listの生成はArraysの方が好きだな。
LocationConditionsDomain locationConditions = new LocationConditionsDomainImpl() {{ setDepth( DepthDomain.INFINITY ); setList( Arrays.asList( new LocationConditionDomain[] { new LocationConditionDomainImpl() {{ setObjectIdentity( new ObjectIdentityDomainImpl() {{ setId("hoge"); }} ); }} ), new LocationConditionDomainImpl() {{ setObjectIdentity( new ObjectIdentityDomainImpl() {{ setId("foo"); }} ); }} ), new LocationConditionDomainImpl() {{ setObjectIdentity( new ObjectIdentityDomainImpl() {{ setId("var"); }} ); }} ) })); }};
こんな感じ。最初のと比べるとだいぶスマートかと。オブジェクトの階層が一目でわかるのがいい。
で、気になるのは次の3点。
- 匿名クラスでインスタンスイニシャライザを追加する方法なので、イニシャライザで使う引数はfinalでないといけない。このせいで使いにくい場面はありそう。
- クラスがfinalの場合使えない。(当たり前)
- あと、匿名クラスを使うことによるオーバーヘッドがないかも気になるところ。今度測ってみよう。