- 締切済み
Static Initializerについて
JavaWorld Online - Javaの“常識”、“非常識” 第3回 http://www.javaworld.jp/technology_and_programming/-/27074-5.html 上記のURL内の記述によると 「static変数の初期化は、そのstatic変数を宣言する際、同時に行うことができます。しかし、宣言時ではなく、実行時に初期化したいというケースもあるでしょう。そのような場合に、この静的初期化子を使用します。」 とあり、宣言時の初期化とStatic Initializerを使用した場合でタイミングが異なると読み取れる記述があります。 が、意味がよく分かりませんでした。Date型を現在日付で初期化する簡単なプログラムで確認したのですが、同じタイミングで初期化されるように見えました。正確には変数が初期化された直後にStatic Initializerが動いてました。 そしてこの順番は(私のプログラムでは)インスタンス化する場合と、インスタンス化せずにstatic publicで定義しているクラス変数にアクセスする場合ともに結果は同じでした。 もしかしたらHPの記述が間違っているのかなーとも思いますがよく分かりません。 知りたいのは両者のタイミングの違いです。 Static Initializerについてご存知の方よろしくお願いします。 ※字数の関係から今回はソースを添付できませんでしたが、ご希望があれば質問の補足で添付します。
- みんなの回答 (7)
- 専門家の回答
みんなの回答
- UKY
- ベストアンサー率50% (604/1207)
> 宣言による初期化は静的変数間の初期化順序が規定されません。 いやいや、それは嘘。 宣言時の初期化であるか static initializer による初期化であるかの区別なく、ソースコードに書いてある順番の通りに初期化されることになっています。 実際、static initializer を宣言より先に書くことだってできます。 class Temp { static { System.out.println("Init:" + Temp.a); a = 3; } static int a = 1; public static void main(String[] args) { System.out.println("main:" + a); } } これを実行すると、 Init:0 main:1 と表示されます。
皆さんも回答して下さっていますが、 例えば変数宣言だけでは定義されない場合があります。 例えば、Mapを定義する場合はインスタンスは定義できますが、中身まで設定できませんよね。 その場合には、Static Initializerを使って定義します。 static final Map map = new HashMap(); static { map.put("ONE", "1"); map.put("TWO", "2"); }
お礼
>Mapを定義する場合はインスタンスは定義できますが、 >中身まで設定できませんよね。 可能か不可能かでいえば可能です。 そのようなハッシュの内容を返すメソッドを作成し、 それを呼び出せば宣言時に初期化が可能です。 質問はそのような点を問題にしているのではありません。 繰り返しになりますが、私は 「宣言時ではなく実行時に初期化したいというケースもある」 という言葉に疑問を持っています。 回答者の方には「…のような場合には出来ないから」 という回答をしてくださる方が多いのですが、 私が問題にしているのは「出来る、出来ない」ではありません。 そもそも、論理的な構造としてはいかなる初期化処理も 「宣言時に出来ない」ことはありません。 私が問題にしているのは、説明文中の記述の 「したい、したくない」という点です。 処理を記述できる出来ないという点以外に 変数の初期化だけに着目した場合に、 有用性の差があると取れる記述があるので、 それは何かということに疑問を持っています。
- BLUEPIXY
- ベストアンサー率50% (3003/5914)
> 2つのケースの間に、実効的な違いが存在するのか、 例えば、 大量の配列の初期化をしたい場合、全てを並びで書くのは、ムリというような場合とか、 Static Initializer の場合、実行文が書けるというのが違うと思います。
お礼
見易さを考慮して、表記方法の多様性を持たせるためだけに 用意されたということですね。 JavaWorld のサイトの記述の 「宣言時ではなく実行時に初期化したいというケースもある」 という説明は間違っているというご回答ということでよろしいでしょうか? もしそうであるなら、納得なんですけど… ありがとうございました。
- bgbg
- ベストアンサー率53% (94/175)
> 2つのケースの間に、実効的な違いが存在するのか、 実効的な違いは存在します。 クラスがロードされるタイミングにより初期化する値を変えたいとか、 staticブロック内で何らかの条件分岐をさせたいとか。 たとえば、 static final int a; static{ if(AnotherClass.value > 0) a = 1; else a = 2; } このような処理をさせたい時とか。 宣言時に一緒に初期化してしまうとこのような分岐処理はできないですから。 「分岐処理なんて初期化の時にやならくても」と考えるかもしれませんが、 ユーザには「初期化時に何らかの分岐処理をしている」ことを意識させたくない場合もあります。 そのような時に威力を発揮するのではないでしょうか。
お礼
くだらない揚げ足取りになってしまいますが、ご提示された例の場合、私なら下記のように宣言時に初期化することができます。 static final int a = AnotherClass.value > 0 ? 1 :2;
- rinkun
- ベストアンサー率44% (706/1571)
静的変数の宣言による初期化と静的初期化子での初期化は前者が後者より先に実行されるだけでタイミング的には大きな違いは生じないでしょう。 しかし、宣言による初期化は静的変数間の初期化順序が規定されません。それに対して静的初期化子での初期化は記述順に実行されます。 従って、初期化の際に同じクラス内の他の静的変数の値を参照しなければいけない場合は静的初期化子を使う必要があります。
- bgbg
- ベストアンサー率53% (94/175)
静的変数の初期は以下のような形で通常行うと思います。 static int a = 10; これは変数の宣言と初期化が一緒になっています。これを別々に実行しようとすると、 static int a; static{ a = 10; } という書き方になります。 リンク先の記事が言わんとすることは、このように静的変数の宣言と初期化を分離できます、ということです。 また、staticブロックでは初期化以外のいろいろな処理も行うことが出来ます(printlnとか) ということで、リンク先の記事の内容が間違っているということはないです。 ただ、ミスリードさせる表現が多いような気がするので、勘違いしても仕方ないでしょう。 なお、 > なお、静的初期化子では、例外を発生させることができないため、例外が発生しない処理、 > あるいは例外が発生しても問題のない処理のみを記述するように注意してください。 と書かれていますが、静的初期化子内では例外をthrowすることができないだけでtry-catchを使った例外処理自体は問題なく行えます。 これもミスリードしそうな書き方になってますね。。。
お礼
ご回答ありがとうございます。 …なるほど。少しだけ分かりました。 >宣言時ではなく、実行時に初期化したい >というケースもあるでしょう。 最大の疑問点はここなんです。 「宣言時ではなく実行時に初期化したい」 とわざわざ書くということは、 「宣言時」と「実行時」はタイミングもしくは役割が違うはずだ と思うのですが、その違いが私には分かりませんでした。 ただ単に別の行に書くというレベルことのでしかないのか、 それとも論理的に意味のある区別なのかがよく分かりません。 私の今の理解では、 ・Static Initializerは初期化に関係しない処理も記述することが出来る。 ・「宣言」が行われた後必ず「実行」される ・タイミングは同一とみなせる ・変数の初期化という観点のみに着目した場合、両者に実効的な違いはない という認識しかありません。 質問を明確化します。 宣言の初期化という観点のみに着目した場合、 「宣言時」と「実行時(Static Initializer)」で変数の初期化を行う 2つのケースの間に、実効的な違いが存在するのか、 もしあるのならその違いを具体的に教えてほしい です。 よろしくお願いします。
両者というのは、 変数宣言の初期化と、Static Initializerということでよろしいですか? この記事にも書いてありますが、 両者の実行されるタイミングは、クラスがクラスローダーによって読み込まれた時です。 厳密には、変数の宣言が先になると思います。 ”全くの同時に処理が実行する”のは物理的に無理です。 インスタンス化する場合も、インスタンス化しないでstatic参照する場合も、そのクラスのアクションが実行されるには、クラスをクラスローダーによって読み込む必要があります。 なので、インスタンス化した場合も、static参照した場合でも、Static Initializerが実行されるタイミングは同じだと言えます。
お礼
ご回答ありがとうございます。 私は 「宣言時ではなく実行時に初期化したいというケースもある」 という言葉に疑問を持っています、 例として 「initString = System.getProperty("init.string");」 こんなコードを挙げています。 実際試しましたが、「宣言時」でも「実行時」でも 有意な差異は認められませんでした。 また例外が発生する可能性のある処理でも挙動は変わりませんでした。 私はタイミングがぴったり同じだとは思っておらず、 「宣言時」が先であることを確認したのは質問欄に記述したとおりです。 私が疑問に思っているのはぴったり同じか少しタイミングがずれるのか ということではありません。 説明文の中で 「宣言時」と「実行時」を区別して使用していること、 「宣言時ではなく実行時に初期化したいというケースもある」というように 「宣言時」と「実行時」を役割的にも区別して 記述している点に疑問を持っています。 もっと端的に言えば、 「なぜ宣言時ではダメなのか」 という点に行き着きます。 質問を少し変えます ・「宣言時ではなく…」という表現が適切か、正しいか ・正しいならば、なぜ宣言時ではダメなのか です。 よろしくお願いします。
お礼
私の疑問は 「宣言時ではなく実行時に初期化したいというケースもある」 という言葉にありました。 言葉から、 「どちらでも行うことは出来るが実行時に行う方がやや都合がよい」 と解釈し、その理由を解消したいと思っていました。 私の質問が悪かったということもあると思いますが、 その点を解消することは出来ませんでした。 ただ、最初の質問には >知りたいのは両者のタイミングの違いです。 と記述しています。 タイミングの違いについて新たな情報をいただいた #7さんに少しだけポイントを付与させていただくことにします。 ご回答していただいた皆様、ありがとうございました。 この点についてはまだ疑問が残っているので 整理して再質問させていただくと思います。 その際にはよろしくお願いします。