簡體   English   中英

Java switch 語句:需要常量表達式,但它是常量

[英]Java switch statement: Constant expression required, but it IS constant

所以,我正在研究這個有一些靜態常量的類:

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

我知道編譯器需要在編譯時知道表達式才能編譯開關,但為什么 Foo.BA_ 不是常量?

雖然從初始化字段后執行的任何代碼的角度來看,它們是常量,但它們不是 JLS 要求的編譯時間常量 有關常量表達式1的規范,請參見第 15.28 節常量表達式 這指的是§4.12.4 最終變量,它定義了一個“常量變量”,如下所示:

我們將原始類型或 String 類型的變量稱為 final 並使用編譯時常量表達式(第 15.28 節)初始化的變量為常量變量。 變量是否為常量變量可能對類初始化(§12.4.1)、二進制兼容性(§13.1、§13.4.9)和明確賦值(§16)有影響。

在您的示例中, Foo.BA* 變量沒有初始化程序,因此不符合“常量變量”的條件。 修復很簡單; 將 Foo.BA* 變量聲明更改為具有編譯時常量表達式的初始化程序。

在其他示例中(初始化程序已經是編譯時常量表達式),可能需要將變量聲明為final

您可以更改代碼以使用enum而不是int常量,但這會帶來另外幾個不同的限制:


1 - 常量表達式的限制可以總結如下。 常量表達式 a) 只能使用原始類型和String ,b) 允許作為文字的主元素(除了null )和常量變量,c) 允許可能作為子表達式括起來的常量表達式,d) 允許除賦值運算符之外的運算符, ++ , --instanceof和 e) 只允許類型轉換為原始類型或String

請注意,這不包括任何形式的方法或 lambda 調用、 new.class .length或數組下標。 此外,由於 a),任何使用數組值、 enum值、原始包裝類型的值、裝箱和拆箱都被排除在外。

需要常量表達式,因為您將值從常量中刪除。 嘗試:

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

我在 Android 上遇到了這個錯誤,我的解決方案就是使用:

public static final int TAKE_PICTURE = 1;

代替

public static int TAKE_PICTURE = 1;

因為那些不是編譯時常量。 考慮以下有效代碼:

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

您可以像本例中那樣使用枚舉:

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;
    }
  }
}

我建議使用以下方式:

public enum Animal {
    DOG("dog"), TIGER("tiger"), LION("lion");
    private final String name;

    @Override
    public String toString() {
        return this.name;
    }
}


public class DemoSwitchUsage {

     private String getAnimal(String name) {
         Animal animalName = Animal.valueOf(name);
         switch(animalName) {
         case DOG:
             // write the code required.
             break;
         case LION:
             // Write the code required.
             break;
         default:
             break;
         }
     }
}

這是很久以前回答的,可能不相關,但以防萬一。 當我遇到這個問題時,我只是使用if<\/code>語句而不是switch<\/code> ,它解決了錯誤。 這當然是一種解決方法,可能不是“正確”的解決方案,但就我而言,這已經足夠了。

編輯:2021.01.21<\/h3>

這個答案有點誤導,我想澄清一下。

    if<\/code>替換switch<\/code>語句不應該被視為 goto 解決方案,有很好的理由說明switch<\/code>和if<\/code>的概念存在於軟件開發中,以及在兩者之間進行選擇時要考慮的性能問題。<\/li>
  1. 盡管我為出現的錯誤提供了解決方案,但我的回答沒有說​​明問題發生的“原因”,而是提供了解決問題的方法。<\/li><\/ol>

    在我的具體情況下,使用if<\/code>語句就足以解決問題。 開發人員應該花時間決定這是否是您手頭當前問題的正確解決方案。

    因此,如我在第一個回復中所述,此答案應僅被視為特定情況下的解決方法,而絕不是此問題的正確答案

如果您在開關盒中使用它,那么您需要在將該值插入開關之前獲取枚舉的類型。 例如 :

SomeEnum someEnum = SomeEnum.values()[1];

枚舉就像:

就我而言,我得到了這個例外,因為

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

在第二種情況下,我從實例var.MODIFICAR_KM:但我應該直接從類中使用VariablesKmDialog.OBTENER_KM

下面的代碼是不言自明的,我們可以使用帶有開關盒的枚舉:

/**
 *
 */
enum ClassNames {
    STRING(String.class, String.class.getSimpleName()),
    BOOLEAN(Boolean.class, Boolean.class.getSimpleName()),
    INTEGER(Integer.class, Integer.class.getSimpleName()),
    LONG(Long.class, Long.class.getSimpleName());
    private Class typeName;
    private String simpleName;
    ClassNames(Class typeName, String simpleName){
        this.typeName = typeName;
        this.simpleName = simpleName;
    }
}

有時switch 變量也會導致該錯誤,例如:

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

   //...
}

在執行以下操作時在 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

            }

問題在於 int 和 Integer(我不知道為什么),將 int 更改為 string 並且它可以工作

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

我建議你使用枚舉:)

看一下這個:

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());

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM