web-dev-qa-db-ja.com

Java switchステートメント:定数式が必要ですが、IS定数

それで、私はいくつかの静的定数を持つこのクラスに取り組んでいます:

public abstract class Foo {
    ...
    public static final int BAR;
    public static final int BAZ;
    public static final int BAM;
    ...
}

次に、定数に基づいて関連する文字列を取得する方法が欲しいです:

public static String lookup(int constant) {
    switch (constant) {
        case Foo.BAR: return "bar";
        case Foo.BAZ: return "baz";
        case Foo.BAM: return "bam";
        default: return "unknown";
    }
}

ただし、コンパイルすると、3つのケースラベルのそれぞれでconstant expression requiredエラーが発生します。

コンパイラーは、スイッチをコンパイルするために、コンパイル時に式を認識する必要があることを理解していますが、なぜFoo.BA_定数ではないのですか?

147
Austin Hyde

コンパイラーは、スイッチをコンパイルするためにコンパイル時に式を知っている必要があることを理解していますが、なぜFoo.BA_が一定ではないのですか?

これらは、フィールドが初期化された後に実行されるコードの観点からは一定ですが、JLSが必要とする意味ではコンパイル時定数ではありません。 定数式の指定については §15.28定数式 を参照してください1。これは §4.12.4最終変数 を指し、次のように「定数変数」を定義します。

プリミティブ型またはString型の変数を呼び出します。これは最終変数であり、コンパイル時の定数式(§15.28)で初期化された定数変数です。変数が定数変数であるかどうかは、クラスの初期化(§12.4.1)、バイナリ互換性(§13.1、§13.4.9)、および明確な割り当て(§16)に影響を与える可能性があります。

あなたの例では、Foo.BA *変数には初期化子がないため、「定数変数」としての資格はありません。修正は簡単です。 Foo.BA *変数宣言を変更して、コンパイル時の定数式である初期化子を持たせます。

他の例(初期化子が既にコンパイル時の定数式である場合)では、変数をfinalとして宣言することが必要な場合があります。

enum定数ではなくint定数を使用するようにコードを変更することもできますが、それには別の制限がいくつかあります。

  • defaultの既知の値ごとにcaseが存在する場合でも、mustenumケースを含めます。 enumのスイッチにデフォルトが必要な理由 を参照してください
  • caseラベルは、enum値に評価される式ではなく、すべて明示的なenum値でなければなりません。

1-定数式の制限は次のように要約できます。定数式a)プリミティブ型とStringのみを使用でき、b)リテラル(nullを除く)および定数変数のみを許可、c)おそらくサブ式として括弧で囲まれた定数式を許可、d)代入演算子、++を除く演算子を許可--またはinstanceof、およびe)プリミティブ型への型キャストまたはStringのみを許可します。

これには、メソッドまたはラムダ呼び出しの形式new.classは含まれないことに注意してください。 .lengthまたは配列の添字。さらに、配列値、enum値、プリミティブラッパータイプの値、ボックス化およびボックス化解除の使用は、a)のためにすべて除外されます。

135
Stephen C

定数式が必要を取得します。これは、定数から値を削除したためです。試してください:

public abstract class Foo {
    ...
    public static final int BAR=0;
    public static final int BAZ=1;
    public static final int BAM=2;
    ...
}
69
Tony Ennis

Androidでこのエラーが発生しましたが、私の解決策は次のとおりです:

public static final int TAKE_PICTURE = 1;

の代わりに

public static int TAKE_PICTURE = 1;
41
Teo Inke

それらはコンパイル時定数ではないからです。次の有効なコードを検討してください。

public static final int BAR = new Random().nextInt();

実行時にBARの値のみを知ることができます。

29

この例のような列挙型を使用できます。

public class MainClass {
enum Choice { Choice1, Choice2, Choice3 }
public static void main(String[] args) {
Choice ch = Choice.Choice1;

switch(ch) {
  case Choice1:
    System.out.println("Choice1 selected");
    break;
 case Choice2:
   System.out.println("Choice2 selected");
   break;
 case Choice3:
   System.out.println("Choice3 selected");
   break;
    }
  }
}

ソース: 列挙型のSwitchステートメント

17
thenosic

これは何年も前に回答されたもので、おそらく関連性はありませんが、念のためです。この問題に直面したとき、ifの代わりにswitchステートメントを使用しただけで、エラーが解決しました。もちろんこれは回避策であり、おそらく「正しい」ソリューションではありませんが、私の場合はそれで十分でした。

4
Samer Murad

スイッチ変数は、たとえば次のようなエラーを引き起こすこともあります。

switch(view.getTag()) {//which is an Object type

   case 0://will give compiler error that says Constant expression required

   //...
}

解決するには、変数をintにキャストする必要があります(この場合)。そう:

switch((int)view.getTag()) {//will be int

   case 0: //No Error

   //...
}
0
Mahdi-Malv

私の場合、私はこの例外を受け取っていました

switch (tipoWebServ) {
                            case VariablesKmDialog.OBTENER_KM:
                                resultObtenerKm(result);
                                break;
                            case var.MODIFICAR_KM:
                                resultModificarKm(result);
                                break;
                        }

2番目のケースでは、インスタンスvar.MODIFICAR_KM:から定数を呼び出していましたが、クラスから直接VariablesKmDialog.OBTENER_KMを使用する必要があります。

0
Gian Gomen

列挙型を使用することをお勧めします:)

これをチェックしてください:

public enum Foo 
{
    BAR("bar"),
    BAZ("baz"),
    BAM("bam");

    private final String description;

    private Foo(String description)
    {
        this.description = description;
    }

    public String getDescription()
    {
        return description;
    }
}

その後、次のように使用できます。

System.out.println(Foo.BAR.getDescription());
0
everton

このようなことをしているときに、Androidでこのエラーが発生しました。

 roleSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

            switch (parent.getItemAtPosition(position)) {
                case ADMIN_CONSTANT: //Threw the error

            }

定数を宣言しているにもかかわらず:

public static final String ADMIN_CONSTANT= "Admin";

コードを次のように変更して問題を解決しました。

roleSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

            String selectedItem = String.valueOf(parent.getItemAtPosition(position));
            switch (selectedItem) {
                case ADMIN_CONSTANT:

            }
0