2011-08-25 8 views
9

私は非常に奇妙なバグに遭遇し、なぜそれが起こるのか説明できません。Javaの列挙定数の初期化が完了していないのはなぜですか?

import java.awt.Color; 

public class test { 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     System.out.println(MyEnum.CONSTANT1.get()); 
     System.out.println(MyEnum.CONSTANT2.get()); 
    } 

    private enum MyEnum { 
     CONSTANT1(staticMethod1()), 
     CONSTANT2(staticMethod2()); 

     private static final Color WHY_AM_I_NULL = new Color(255, 255, 255); 

     private final Color color; 

     private MyEnum(Color color) { 
      this.color = color; 
     } 

     public Color get() { 
      return color; 
     } 

     private static Color staticMethod1() { 
      return new Color(100, 100, 100); 
     } 

     private static Color staticMethod2() { 
      return WHY_AM_I_NULL; 
     } 
    } 

} 

結果をあなたがこれを実行します:秒1がヌルである理由

java.awt.Color[r=100,g=100,b=100] 
null 

質問は、ある次のenumを想像してみ?

Ammendment: あなたが列挙型の内側にプライベート静的クラスでWHY_AM_I_NULLを入れた場合は、それが最初に初期化されます。

+0

は、また新たな観測 –

+1

をAmmended場合メソッドではなく定数を直接使用しようとすると、Eclipseにエラーが表示されます。これは、静的メソッドを使用する場合には当てはまりません。 FindBugsでも問題はありません!私はこれが警告に値すると思う少なくとも –

答えて

12

問題は、すべての静的フィールド(および列挙インスタンスはそのようにカウントされる)は、宣言された順番(specification)で初期化されることです。したがって、CONSTANT2がインスタンス化されると、フィールドWHY_AM_I_NULLはまだ初期化されていません(したがって、null)。

フィールドをenumインスタンスの前に置くことはできないので、フィールドをenumクラスの外に置くなど、必要な作業を行う必要があります。あなたが本当に欲しいものを私たちに教えていただければ、さらなる提案をすることができます。

編集:ネストしたクラスでWHY_AM_I_NULLを入れた場合は、このクラスのフィールドは、すぐにクラスが最初にアクセスされるように初期化されます(つまり、staticMethod2の実行中にこの場合)。

+0

私はちょうど列挙定数の初期化で使用される定数をしたい。列挙型の中の私的静的クラスに定数を置くと、うまくいきました。 このEnumのユーザーはこの内部定数を気にせず、複数回宣言する必要はありません(または、色を作成するメソッドとして複数回作成した場合) –

+1

この場合私は確かに静的入れ子クラスをフィールド保持者クラスとして使用します。 –

4

列挙型はコンパイラ機能です。実際には、コンパイラは2つのパブリック静的フィールドCONSTANT1とCONSTANT2と他のコードを含むMyEnumという名前のクラスを作成します。

スタティック初期化はアップからダウンに行われるため、CONSTANT2が作成され、静的変数WHY_AM_I_NULLより前に初期化されます。これは、CONSTANT2が初期化されているときにWHY_AM_I_NULLがNULLになる理由です。

1

これは、静的フィールド(列挙値を含む)がファイル内に表示される順序で初期化されるためです。

ので CONSTANT1

、およびCONSTANT2したがってCONSTANT2nullで初期化され、WHY_AM_I_NULL前に初期化されます。

2

WHY_AM_I_NULLstaticMethod2が呼び出されたときにnullである - これはJLSがあなたの代わりに100, null100, 255を取得したい異なる順序で初期化

を指定する方法である:

private static final Color WHY_AM_I_NULL = new Color(255, 255, 255); 
private enum MyEnum { 
    CONSTANT1(staticMethod1()), 
    CONSTANT2(staticMethod2()); 
    //... 
+0

-1。フィールドが列挙型の内部で初期化されていない理由についても、列挙型の外でどのように動作するかを示すことによって問題を迂回させているのです。もう一つ注意してほしい点は、**「それはそれがどのように指定されたのために起こるのか」というのは正解ではありません。** [回答方法​​]を参照してください(http://softwareengineering.stackexchange.com/help/how-to-回答) –

関連する問題