• 締切済み

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についてご存知の方よろしくお願いします。 ※字数の関係から今回はソースを添付できませんでしたが、ご希望があれば質問の補足で添付します。

  • Java
  • 回答数7
  • ありがとう数8

みんなの回答

  • UKY
  • ベストアンサー率50% (604/1207)
回答No.7

> 宣言による初期化は静的変数間の初期化順序が規定されません。 いやいや、それは嘘。 宣言時の初期化であるか 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 と表示されます。

arakororin
質問者

お礼

私の疑問は 「宣言時ではなく実行時に初期化したいというケースもある」 という言葉にありました。 言葉から、 「どちらでも行うことは出来るが実行時に行う方がやや都合がよい」 と解釈し、その理由を解消したいと思っていました。 私の質問が悪かったということもあると思いますが、 その点を解消することは出来ませんでした。 ただ、最初の質問には >知りたいのは両者のタイミングの違いです。 と記述しています。 タイミングの違いについて新たな情報をいただいた #7さんに少しだけポイントを付与させていただくことにします。 ご回答していただいた皆様、ありがとうございました。 この点についてはまだ疑問が残っているので 整理して再質問させていただくと思います。 その際にはよろしくお願いします。

noname#19197
noname#19197
回答No.6

皆さんも回答して下さっていますが、 例えば変数宣言だけでは定義されない場合があります。 例えば、Mapを定義する場合はインスタンスは定義できますが、中身まで設定できませんよね。 その場合には、Static Initializerを使って定義します。 static final Map map = new HashMap(); static { map.put("ONE", "1"); map.put("TWO", "2"); }

arakororin
質問者

お礼

>Mapを定義する場合はインスタンスは定義できますが、 >中身まで設定できませんよね。 可能か不可能かでいえば可能です。 そのようなハッシュの内容を返すメソッドを作成し、 それを呼び出せば宣言時に初期化が可能です。 質問はそのような点を問題にしているのではありません。 繰り返しになりますが、私は 「宣言時ではなく実行時に初期化したいというケースもある」 という言葉に疑問を持っています。 回答者の方には「…のような場合には出来ないから」 という回答をしてくださる方が多いのですが、 私が問題にしているのは「出来る、出来ない」ではありません。 そもそも、論理的な構造としてはいかなる初期化処理も 「宣言時に出来ない」ことはありません。 私が問題にしているのは、説明文中の記述の 「したい、したくない」という点です。 処理を記述できる出来ないという点以外に 変数の初期化だけに着目した場合に、 有用性の差があると取れる記述があるので、 それは何かということに疑問を持っています。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.5

> 2つのケースの間に、実効的な違いが存在するのか、 例えば、 大量の配列の初期化をしたい場合、全てを並びで書くのは、ムリというような場合とか、 Static Initializer の場合、実行文が書けるというのが違うと思います。

arakororin
質問者

お礼

見易さを考慮して、表記方法の多様性を持たせるためだけに 用意されたということですね。 JavaWorld のサイトの記述の 「宣言時ではなく実行時に初期化したいというケースもある」 という説明は間違っているというご回答ということでよろしいでしょうか? もしそうであるなら、納得なんですけど… ありがとうございました。

  • bgbg
  • ベストアンサー率53% (94/175)
回答No.4

> 2つのケースの間に、実効的な違いが存在するのか、 実効的な違いは存在します。 クラスがロードされるタイミングにより初期化する値を変えたいとか、 staticブロック内で何らかの条件分岐をさせたいとか。 たとえば、 static final int a; static{  if(AnotherClass.value > 0)   a = 1;  else   a = 2; } このような処理をさせたい時とか。 宣言時に一緒に初期化してしまうとこのような分岐処理はできないですから。 「分岐処理なんて初期化の時にやならくても」と考えるかもしれませんが、 ユーザには「初期化時に何らかの分岐処理をしている」ことを意識させたくない場合もあります。 そのような時に威力を発揮するのではないでしょうか。

arakororin
質問者

お礼

くだらない揚げ足取りになってしまいますが、ご提示された例の場合、私なら下記のように宣言時に初期化することができます。 static final int a = AnotherClass.value > 0 ? 1 :2;

  • rinkun
  • ベストアンサー率44% (706/1571)
回答No.3

静的変数の宣言による初期化と静的初期化子での初期化は前者が後者より先に実行されるだけでタイミング的には大きな違いは生じないでしょう。 しかし、宣言による初期化は静的変数間の初期化順序が規定されません。それに対して静的初期化子での初期化は記述順に実行されます。 従って、初期化の際に同じクラス内の他の静的変数の値を参照しなければいけない場合は静的初期化子を使う必要があります。

  • bgbg
  • ベストアンサー率53% (94/175)
回答No.2

静的変数の初期は以下のような形で通常行うと思います。 static int a = 10; これは変数の宣言と初期化が一緒になっています。これを別々に実行しようとすると、 static int a; static{  a = 10; } という書き方になります。 リンク先の記事が言わんとすることは、このように静的変数の宣言と初期化を分離できます、ということです。 また、staticブロックでは初期化以外のいろいろな処理も行うことが出来ます(printlnとか) ということで、リンク先の記事の内容が間違っているということはないです。 ただ、ミスリードさせる表現が多いような気がするので、勘違いしても仕方ないでしょう。 なお、 > なお、静的初期化子では、例外を発生させることができないため、例外が発生しない処理、 > あるいは例外が発生しても問題のない処理のみを記述するように注意してください。 と書かれていますが、静的初期化子内では例外をthrowすることができないだけでtry-catchを使った例外処理自体は問題なく行えます。 これもミスリードしそうな書き方になってますね。。。

参考URL:
http://www.y-adagio.com/public/standards/tr_javalang2/classes.doc.html#38013
arakororin
質問者

お礼

ご回答ありがとうございます。 …なるほど。少しだけ分かりました。 >宣言時ではなく、実行時に初期化したい >というケースもあるでしょう。 最大の疑問点はここなんです。 「宣言時ではなく実行時に初期化したい」 とわざわざ書くということは、 「宣言時」と「実行時」はタイミングもしくは役割が違うはずだ と思うのですが、その違いが私には分かりませんでした。 ただ単に別の行に書くというレベルことのでしかないのか、 それとも論理的に意味のある区別なのかがよく分かりません。 私の今の理解では、 ・Static Initializerは初期化に関係しない処理も記述することが出来る。 ・「宣言」が行われた後必ず「実行」される ・タイミングは同一とみなせる ・変数の初期化という観点のみに着目した場合、両者に実効的な違いはない という認識しかありません。 質問を明確化します。 宣言の初期化という観点のみに着目した場合、 「宣言時」と「実行時(Static Initializer)」で変数の初期化を行う 2つのケースの間に、実効的な違いが存在するのか、 もしあるのならその違いを具体的に教えてほしい です。 よろしくお願いします。

noname#19197
noname#19197
回答No.1

両者というのは、 変数宣言の初期化と、Static Initializerということでよろしいですか? この記事にも書いてありますが、 両者の実行されるタイミングは、クラスがクラスローダーによって読み込まれた時です。 厳密には、変数の宣言が先になると思います。 ”全くの同時に処理が実行する”のは物理的に無理です。 インスタンス化する場合も、インスタンス化しないでstatic参照する場合も、そのクラスのアクションが実行されるには、クラスをクラスローダーによって読み込む必要があります。 なので、インスタンス化した場合も、static参照した場合でも、Static Initializerが実行されるタイミングは同じだと言えます。

arakororin
質問者

お礼

ご回答ありがとうございます。 私は 「宣言時ではなく実行時に初期化したいというケースもある」 という言葉に疑問を持っています、 例として 「initString = System.getProperty("init.string");」 こんなコードを挙げています。 実際試しましたが、「宣言時」でも「実行時」でも 有意な差異は認められませんでした。 また例外が発生する可能性のある処理でも挙動は変わりませんでした。 私はタイミングがぴったり同じだとは思っておらず、 「宣言時」が先であることを確認したのは質問欄に記述したとおりです。 私が疑問に思っているのはぴったり同じか少しタイミングがずれるのか ということではありません。 説明文の中で 「宣言時」と「実行時」を区別して使用していること、 「宣言時ではなく実行時に初期化したいというケースもある」というように 「宣言時」と「実行時」を役割的にも区別して 記述している点に疑問を持っています。 もっと端的に言えば、 「なぜ宣言時ではダメなのか」 という点に行き着きます。 質問を少し変えます ・「宣言時ではなく…」という表現が適切か、正しいか ・正しいならば、なぜ宣言時ではダメなのか です。 よろしくお願いします。

関連するQ&A

  • static付き宣言の初期化

    static付きの宣言をした場合の変数の初期化について教えてください。(ANSI-C) int func(void) { static int si; static char sca[10]; static char *scp; /* 何らかの処理 */ return 0; } このように関数内でstatic付きで宣言したとき、変数はどのように初期化されますか? siは0、sca[0]からsca[9]までは'\0'、scpはNULLで初期化されますか? また、このようなstatic付きの宣言が関数の外にあった場合は、どのように初期化されますか?

  • C言語のStatic変数について

    現在、C言語の勉強しながらゲームプログラムにチャレンジしています。 二つの関数で利用する変数を作りたかったので、Static宣言された変数を容易しました。 ですが、この変数、一度処理が終わると当面使わない変数なのです。 (ただし、処理途中は何度も呼び出されるので値は保持しなければいけません) よって、メモリ上に延々居座られるのが邪魔に思えて仕方ありません。 実際、大したことないだろうとは思うのですが。 このStaticで宣言された変数を、自分の好きなタイミングでメモリ上から解放するような処理はできませんか? もしくはメモリ上に居座ることのない処理の仕方などありましたら、 考え方を教えていただけるとうれしいです。よろしくお願いします。

  • static宣言について

    現在、c言語とDXライブラリを使ってゲームを製作しています。 http://okwave.jp/qa/q8270456.html 前回、このような質問をさせていただき、原因らしき箇所を突き止める所までいきました。 と言いますのも、配列の要素を指定する箇所(分かり辛かったらすいません。要素数ではありません)に、static宣言された変数を入れるとなぜかプログラムが強制終了されてしまうのです。 加えて、DXライブラリのGetColor関数にも返ってきた色をStatic宣言された変数に格納すると、何故か指定された色と違う色が出てしまうことが分かりました。 なんとか、その関数が終わる度に値を格納したかったので、色々試しました。 直接Static宣言されていない変数を間に噛ませてみたり、同じcpp内にわざわざ別の関数を用意して、そちらでStatic宣言し、値を返してみたり、と色々とやったのですが上手くいきませんでした。 ****************************************** int hairetu[20]; Static int z = 0; int x = z-1+1 hairetu[x] = zahyouX; (static宣言された変数zでhairetu[]の[]内を指定しようとするとダメ) (上記のように意味のない計算をさせてstatic宣言されていない変数を間にかませてもダメ) ****************************************** 結局の所、別のcppを用意して、ただ一つのStatic変数を+1していくだけの関数をくみ上げた所、上手くいったのですが・・・。何故このような事が起きるのでしょうか。 Static宣言された変数の決まりごと、もしくは、このような状態になってしまった原因など、見当がつきましたら教えていただけると有難いです。よろしくお願いします。

  • staticメソッドにするかどうかの判断

    staticメソッドの使いどころについて質問させてください。 まず、メソッドの内部で、そのメソッドが定義されているクラスのイ ンスタンス変数を使用している場合は、そのメソッドはインスタンス に依存するので、インスタンスメソッドにしかできないのはわかり ます。疑問なのは、「じゃあこのメソッド内でインスタンス変数を使 わないで引数で渡せるように作れば、インスタンスに依存しないの でstaticにしていいの?」(※)ということです。 さらにこうも思います。 なんとなくですが、※のようなことをしたらオブジェクト指向の意味 がない気がします。理由ははっきりわかりません。ほんとになんとなく です。(奇跡的にあたっていたとしても、理由を教えて下さいm(_ _)m) そして、さらに混乱するのが、ユーティリティの関数などでstaticメ ソッドになっているのを見ました。この場合はどうしてメソッドの引 数を指定するようにしていて、クラスのインスタンス変数を使うこと はしないのか。 以上、大変下手な文章ですが、混乱しているポイントが伝わったでし ょうか? よろしくお願いします。

  • クラス内の関数内static変数について

    クラス内の「staticではないメンバ関数内で定義される」static変数の初期化タイミングはいつでしょうか? 自分としてはクラスのインスタンス生成時に初期化されるものだと思っていたのですが、どうもそうでは無さそうだという現象に出会ったもので。 例えば以下のようなサンプルプログラムがあるとします。 --------------------------------------- class TA { public: void func(int i); }; void TA::func(int i) { static int d=0; d += i; std::cout << d << std::endl; } int main() { for(int i=1; i < 3;i++) { TA ta; ta.func(i); ta.func(i); ta.func(i); } } --------------------------------------- これを実行した時、自分としては 1 2 3 2 4 6 という結果を期待していた訳ですが、実際には 1 2 3 5 7 9 という結果になりました。 ということは、もしかしてメンバ変数ではなくともクラス内に現れるstatic変数はstaticなメンバ変数と同等ということなのでしょうか? 実際、上記ソースのforループ内にもう一つclass TAのインスタンスtbを追加してみると、 --------------------------------------- for(int i=1; i < 3;i++) { TA ta; ta.func(i); ta.func(i); ta.func(i); TA tb; tb.func(i); tb.func(i); tb.func(i); } --------------------------------------- 1 2 3 4 5 6 8 10 12 14 16 18 となりました。 (まぁstaticではないメンバ変数に置き換えれば一応解決するのですが、個人的に何か凄く気持ち悪く感じて・・・)

  • static 変数について

    static 変数について 今、C++を勉強しているのですか、static変数がどのように動くのかよくわかりません。 下のプログラムのint a はローカル変数だから、ブロックを抜けたら、初期化されるためstatic変数にして、ブロックを抜けても値を保持するようにすってことはわかるのですが 毎回このブロックに入る度、static int a = 0;を読むことになり、その前に入っていた値はなくなるのではないでしょうか?それとも,static int a と書かれていると,1度しか実行されないから、値が保持され続けるのでしょうか? int add (int x ) { int a = 0; a += x; return a; }

  • 「static宣言されているメンバ関数」は、「インスタンスメソッド」な

    「static宣言されているメンバ関数」は、「インスタンスメソッド」なのでしょうか? それとも、「クラスメソッド」なのでしょうか? 先日、下記内容で質問して、その時は分かったつもりだったのですが、 やっぱり分かってなかったようなので、教えてください。 ▽「クラス関数」「メンバ関数」「メソッド」の違いを教えてください。   http://okwave.jp/qa/q5858806.html 例) ▽前提 ・Aクラスのインスタンスa ・static宣言されたpublicメソッド「static_public_method」 ・static宣言されていないpublicメソッド「public_method」 ▽メンバ関数呼び出し ・$a->static_public_method() ・A::static_public_method() ・A::public_method() このとき、「$a->static_public_method()」は、インスタンス経由でアクセスすることになるので、 「インスタンスメソッド」になるのでしょうか。それとも、static(静的)宣言しているので、「クラスメソッド」になるのでしょうか? また、「A::static_public_method()」や、「A::public_method()」は、どちらになるのでしょうか? ※現在、頭の中がこんがらがっているのは、下記3点です。どれかひとつでも構わないので、分かりやすい考え方等あれば、ぜひ教えてください。 ・「static宣言したメンバ関数」は、「インスタンスメソッド」? 「クラスメソッド」? ・「スタティック」宣言してるのに、メンバ関数へ、「->(アロー演算子)」(オブジェクト経由)でアクセスできる理由 ・「A::static_public_method()」と「A::public_method()」の違い

    • ベストアンサー
    • PHP
  • 関数外からstatic変数を再度初期化できるのでしょうか?

    以下の静的変数?についてA,Bのメモリは別でしょうか? test関数外からBの変数を再度初期化できるのでしょうか? staticの仕組みがわからないのでstaticのメモリの初期化のタイミングとメモリアクセス方法について知りたいです。 static x = 1; // ---A int test() { static int x = 0; // --- B } またexternの働きも知りたいです。

  • Struts2でのStaticイニシャライザ

    Struts2でのインターセプターにてStaticイニシャライザを実行するとエラーになってしまいます。 ファイルの絶対パスを取得しようとしています。 以下がそのコードなのですがTomcat再起動時にイニシャライザが実行され getRealPath()の部分で例外が発生し、java.lang.ExceptionInInitializerError が発生します。 同じコードをintercept()メソッド内に記述した場合は例外が発生せず絶対パスを取得することが できます。どなたか原因及び対処方法がおわかりになられますでしょうか。 public class CheckValueInterceptor extends AbstractInterceptor { private static final long serialVersionUID = 1L; //ファイルの絶対パスの取得 static { ServletContext context = ServletActionContext.getServletContext(); String path = context.getRealPath("/WEB-INF/Test.txt"); } public String intercept(ActionInvocation invocation) throws Exception { } }

    • ベストアンサー
    • Java
  • staticのメリット、デメリット

    こんばんは。 staticについて、だんだんわからなくなってきました・・・。 例えばあるクラスの変数で、 static int i = 10; とあった場合、参照クラスからiの値を見ると、必ず10ですよね? static修飾子がついているメソッドの場合、挙動はどうなるのでしょう? staticなメソッドはインスタンス化しなくても呼び出せる。 つまり、メモリ上に1箇所しか存在しないので、同時にアクセスされた場合(synchronizedしていない場合)はどうなるのかがわかりません・・・。 メソッドには引数が存在し、returnがStringやintなどの場合です。 returnは保証(参照側にとって望む値と言う意味で)されるのでしょうか? インスタンス化をしない事によって、パフォーマンスが向上するのでしょうけれど、いまいちメリットがわかりません・・・。 public、privateにかかわらず、メソッドをstatic修飾するメリットを教えてください。 同時にデメリットもお願いします。 以上、下手くそな文章ですみません・・・。 (^^ゞ

    • ベストアンサー
    • Java