2017-02-28 6 views
1

次のコードでreadSide()SIDEを参照し、別の静的変数を初期化するために呼び出されると、SIDEの宣言で割り当てられた値ではなく、ゼロの値が得られます。Javaはコンパイラエラーやランタイムエラーが発生していない初期化されていない最終静的変数をいつ、そしていつ読み込むのですか?

import java.util.Random; 

public class StaticTest { 

    private final static float SIDE_FROM_METHOD = readSide(); 
    private final static float SIDE = 100.0f * new Random().nextFloat(); 

    private static float readSide() { 
     System.out.println("In readSide(): SIDE=" + SIDE); 

     return SIDE; 
    } 

    public static void main(String[] args) { 
     System.out.println("In main(): SIDE_FROM_METHOD=" + SIDE_FROM_METHOD); 
     System.out.println("In main(): SIDE=" + SIDE); 
     System.out.println("In main(): readSide() return=" + readSide()); 
    } 
} 

サンプル出力:SIDEもののだから

In readSide(): SIDE=0.0 
In main(): SIDE_FROM_METHOD=0.0 
In main(): SIDE=85.84305 
In readSide(): SIDE=85.84305 
In main(): readSide() return=85.84305 

が一定であると仮定され、Javaは、それが中で行われる例外をスローするか、その初期化順序を保証いずれかではなく、実行時に値を変更することができ依存関係の順序。

「最終的な静的」オブジェクトを定義する順序は問題のある動作の原因だと思いますが、そのように動作する代わりに例外が発生するのはなぜですか?

SIDEはリテラルではなく、計算された値に初期化されている場合:その後、出力は100.0全体にある...

private final static float SIDE=100.0f; 

In readSide(): SIDE=100.0 
In main(): SIDE_FROM_METHOD=100.0 
In main(): SIDE=100.0 
In readSide(): SIDE=100.0 
In main(): readSide() return=100.0 

なぜこれが違いますか?

+5

奇妙な動作の意味を含めることはできますか? – corriganjc

+0

なぜそれが間違っていますか? –

+0

@corriganjcサンプル出力が質問に追加されました。 – user2999069

答えて

2

定数の定義にはかなり微妙な振る舞いがあります。

ほとんどの場合、final staticの変数は「定数」であると仮定しています。これはプログラミングに取り組むには十分です。

しかしJava Language Specification states in section 4.12.4

(強調鉱山)

プリミティブ型またはString型の変数、すなわち最終とコンパイル時定数式(15.28)で初期化 あります定数変数と呼ばれる です。変数は定数、変数、またはクラス初期化(§12.4.1)、バイナリ互換 (13.1、§13.4.9)及び明確割り当て(§16)に対する影響を有していてもよい 否か

...「コンパイル時定数式」の意味を知るために別のセクションにジャンプしなければなりません。しかし、一言で言えば、100.0fはコンパイル時定数式です。だから100.0f * 10です。コンパイル時には計算できないため、100.0f * new Random().nextFloat()はありません。

最初の例では、SIDEは厳密には定数ではないため、初期化は異なる順序で行われます。詳細はJLS 12.4.1です。

SIDE = 100fにプログラムを変更すると、それは真正なコンパイル時定数になり、したがってルールが変更され、コンパイル時に割り当てられます。

わかったら、これらの問題を回避するのは簡単です。あなたが見てきたように、割り当てを正しい順序で行うだけで症状が改善されます。

+0

あなたは正しい答えを得ているようですが、コンストラクタに置くことについてのアイデアは、(最終的な静的な)ポイントであり、コードサンプルは確実に機能しません。私が考えることができる唯一の修正点は、注文が正しいことを確認するか、この部分を静的なコードブロックに書き込むことです。 – user2999069

+0

@ user2999069あなたが正しいです、コンストラクタについての少しは脳裏であり、私はそれを削除しました。 – slim

1

奇妙な動作は、private final static float[] POINTS = generatePoints();SIDE定数が初期化されていない場合に発生します。問題を解決するには、その行をSIDEの初期化より下に移動してください。すべてのことがうまくいかないのでSIDEが初期化する前に値0.0を開催しますので、例外はありません

理由はgeneratePointsでの計算が0としてその値を読み込むことです。

各タイプにどの値が使用されているかについては、JLS 4.12.5を参照してください。

+0

私はそれを理解していますが、SIDEの値は定義されていないか、定義されているはずです。定数であるため、値を持たないか、エラーまたは正しい値で定義されていますが、コードの実行中に値を変更する定数です。 (これは予想外の動作の定義です) – user2999069

+0

@ user2999069 - 完璧な世界では真実です。私は参照を追加しました。 – OldCurmudgeon

+0

私は変数の初期値を理解していますが、これは定数(最終的な静的浮動小数点数)なので、値を変更すべきではないと思いました。私はEclipse IDEを使用していましたが、メソッドのソースとアルファベット順でメソッドとメンバーを並べ替えるソートメンバーを使用していました(実行の順序がわかっていたのを知っていましたが、 – user2999069

関連する問題