web-dev-qa-db-ja.com

Java静的最終インスタンス変数の列挙

万歳!

このコードはしばらくの間機能しましたが、デフォルトの色を追加することにしましたが、機能しなくなりました。次のエラーが発生します。

1 error found:
File: Status.Java  [line: 20]
Error: Status.Java:20: illegal reference to static field from initializer

コンパイル時に次のコードを使用します。

import Java.awt.Color;

enum Status
{
  OFF ("Off"),
  TRAINING ("Training", new Color(255, 191, 128)),
  BEGINNER ("Beginner", new Color(128, 255, 138)),
  INTERMEDIATE ("Intermediate", new Color(128, 212, 255)),
  ADVANCED ("Advanced", new Color(255, 128, 128));

  public final String name;
  public final Color color;

  public static final Color defaultColor = Color.WHITE;

  Status(String name)
  {
    this(name, defaultColor);
  }
  Status(String name, Color color)
  {
    this.name = name;
    this.color = color;
  }
}

私の知る限り、これは機能するはずですが、何らかの理由でJavaはエラーをスローすることにしました。何か考えはありますか?

15
skeggse

defaultColorは初期化されるだけですコンストラクターが呼び出された-その時までデフォルト値(null)になります。 1つのオプションは、デフォルトの色をネストされたタイプに入れることです。

import Java.awt.Color;

enum Status
{
  OFF ("Off"),
  TRAINING ("Training", new Color(255, 191, 128)),
  BEGINNER ("Beginner", new Color(128, 255, 138)),
  INTERMEDIATE ("Intermediate", new Color(128, 212, 255)),
  ADVANCED ("Advanced", new Color(255, 128, 128));

  public final String name;
  public final Color color;

  Status(String name)
  {
    this(name, Defaults.COLOR);
  }
  Status(String name, Color color)
  {
    this.name = name;
    this.color = color;
  }

  private static class Defaults
  {
     private static Color COLOR = Color.WHITE;
  }
}

もちろん、コードでデフォルトの色onceのみを参照している場合は、コンストラクター呼び出し内でハードコーディングすることもできます。

Status(String name)
{
  this(name, Color.WHITE);
}
28
Jon Skeet

列挙型定数を最初に初期化する必要があります。それらを初期化するには、コンストラクターを呼び出す必要があります。最初のコンストラクターは、呼び出されたときに初期化できなかった可能性のある静的フィールドを参照します。

12
ColinD

Javaはこれを可能にします

class Status
{
    public static final Status OFF = new Status("Off");

    public static final Color defaultColor = Color.WHITE;

    Status(String name)
    {
      this(name, defaultColor);
    }
}

もちろん、実行時に問題が発生しますが、Javaは関係ありません。初期化シーケンスを配置するのはプログラマーの仕事であり、コンパイラーがすべての壊れた初期化依存関係をチェックするのは簡単ではありません。とにかく問題は簡単に修正できます。

class Status
{
    // now it works, this field is initialized first
    public static final Color defaultColor = Color.WHITE;

    public static final Status OFF = new Status("Off");

ただし、enumの場合、この回避策は適用されません。これは、enum型の静的フィールドは、列挙型自体の前に移動できないためです(おそらく純粋な構文上の理由による)。混乱を避けるために、Javaはenumに追加の制限を追加します-静的フィールドはコンストラクターから参照できません。

この制限は中途半端です。コンストラクターから静的フィールドのすべての可能な使用法をチェックすることは(不可能ではないにしても)簡単ではありません。次のコードはコンパイルされ、制限がなくなります。

enum Status
{
    OFF("Off");

    public static final Color defaultColor = Color.WHITE;
    static Color defaultColor(){ return defaultColor; }

    Status(String name)
    {
      this(name, defaultColor());
    }
6
irreputable
0
MJB