先日ハマった現象ですが、Javaプログラミングでとある固定定数を変更してプログラムを動かしたところ、変更前とプログラムの挙動が変わらない・・・。おかしいなと思い色々試してみた所、javaの固定定数に問題があることが分かりました。とういうより忘れていたというのが正確なところでしょうか。
final定数
finalを付けると、プログラムからは通常変数への代入ができなくなるため定数として扱うことが出来ます。
public static final int MAX_NUM = 999;
上記の場合、public staticで定義しているため、いつでもどこからでもこの変数が参照できる状態です。
ここでハマったのが、この変数を利用しているclassたちのことです。
下記のように変更を加えて、修正対象のclassを再コンパイルし対象classのみ入替えました。
public static final int MAX_NUM = 900;
public static final定数はコンパイル時に値が展開される
ここでポイントが、public static final な固定定数を定義した場合、参照される定数は利用先のプログラムをコンパイルする際に固定値として埋め込まれてしまうのです。
具体的には、定数クラスの「const.class」に上記「MAX_NUM」が定義されているとして、実行クラスの「exec.java」が「const.MAX_NUM」を参照しているとします。コンパイルして生成された「exec.class」はこの時点で「MAX_NUM」という変数は既に参照しておらず「999」という値が埋め込まれてしまいます。
後で「MAX_NUM」の値を999→900に変更して「const.class」を入れ替えても、それを参照していた「exec.class」は999の値を保持したままとなります。「exec.class」も同時入替えれば問題は有りませんが、通常は変更したclassしか入替えませんのでアウトです。
対応策
public static final で定義する値は、リテラル関係の定数のみにしましょう。
数値定数関係の値を定義してしまうと、後で変更がかかる可能性がある場合はその値を利用しているclassファイルの再コンパイルが必要になります。
変更される可能性がある値であれば、static finalで定義せず、private static変数とpropertyまたはgetterとしてメソッドを提供し値を取得するように促します。
このようにしておくことでハマることなくプログラムを改修することが可能になります。技術者の方でしたらこんなこと当たり前と思うかもしれませんが、一度作成したプログラムが同じ人が触るとは限りませんので考慮しておくに越したことはありません。
コメント