2009-11-07 6 views
18

自分の職場でJavaコードを見つけることになりました。ここにシナリオがあります:ClassAClassBの2つのクラスがあります。インポートされたJavaクラスのpublic static final変数

ClassAは、その中に4つの静的最終的な文字列値を除いて何もありません。その目的は、ClassA.variableのような値を使用することです(なぜ、私のコードではないかと聞かないでください)。

ClassBインポートClassA。文字列の値をClassAに編集してコンパイルしました。 ClassBを実行したとき、新しい値ではなく古い値を使用していたことがわかりました。 ClassAから新しい値を使用するように、私はClassBを再コンパイルしなければならなかった! (私はClassAをインポートする他のクラスを再コンパイルしなければならなかった!)

これはJDK 1.6のためだけであるか、以前に再コンパイルする必要があったはずですClassB!私を啓発します。 :)

答えて

23

ClassAの変数finalの値がコンパイル時定数になると、コンパイラはランタイム参照を生成する代わりにClassAを使用してクラスにインライン展開する可能性があります。私が思うに、これはあなたが記述した場合に起こったことです。

例:この例では

public class Flags { 
    public static final int FOO = 1; 
    public static final int BAR = 2; 
} 

public class Consumer { 
    public static void main(String[] args) { 
     System.out.println(Flags.FOO); 
    } 
} 

、コンパイラは、おそらくConsumer代わりの等価な実行時間基準を生成するための生成コードにFOOの値を組み込みます。後でFOOの値が変更された場合は、新しい値を使用するためにConsumerを再コンパイルする必要があります。

これは最適化であり、コンパイルされたプログラムの効率と速度に関していくつかの利点があります。 (ここでは:1)の値インライン化、この例では

int x = Flags.FOO * 10; 

:たとえば、値をインライン化すると、例えば、それを使用する式、更なる最適化を、有効かもしれませんが、気づくようにコンパイラができますが、乗算作ること違いはなく、省略することもできます。

+1

public static finalはコンパイル時定数です。それを知らなかった。それは単なる定数であり、実行時に変更することはできないと思った!ご協力いただきありがとうございます。 –

+3

良いアンサー。変数がインライン展開されていることを確認するには、javapを使用してクラスのコンパイル方法を確認します。 "javap -c Flags" –

3

バイナリ互換性の問題です。定数フィールドへの参照はコンパイル時に解決されます。あなたが見ている動作は正しいです。クラスAの値を変更すると、クライアント(クラスB)を再コンパイルする必要があります。このような問題を回避するには、Javaリリース5.0で導入されたenum型を使用して定数を追加することを検討してください。

2

なぜ個々にクラスをコンパイルしようとしていますか?

mavenやantなどのビルドシステムを使用するか、IDEで実行してください。

実行できるすべてのクラスが再コンパイルされるまで、変更されたjavaクラスに依存するすべてのjavaを再コンパイルするだけです。

+0

いずれかのクラスがあなたのコントロール下にない可能性があります。 – DJClayworth

2

あなたが代わりにこれを行うことができますスイッチの値を使用していない場合:

public class A 
{ 
    public static final int FOO; 
    public static final String BAR; 

    static 
    { 
     FOO = 42; 
     BAR = "Hello, World!"; 
    } 
} 

、コンパイラは、もはやハードそれらを使用している他のクラスの値をコード化しません。

2

と仮定にClassAは、次のようになります。あなたはそれを再コンパイルする場合

public class ClassA { 
    public static final int FOO = 1; 
    public static final int BAR = 2; 
} 

は、ClassBのは、古い値を引き続き使用します。私はそれがコンパイラに依存するかもしれないと思うが、これは典型的な動作だと思う。あなたは毎回定数にClassAの変更でClassBのを再コンパイルしたくない場合は、あなたがこのような何かをする必要があります:

public class ClassA { 
    public static final int FOO = CONST(1); 
    public static final int BAR = CONST(2); 

    public static int CONST(int i) { return i; } 
} 

Becuaseは今、javacは、定数をインライン化に消極的です。代わりに、ClassAの静的初期化子が実行されるときにCONST(int)メソッドを呼び出します。

関連する問題