Оператор switch Java: требуется постоянное выражение, но оно постоянное
Итак, я работаю над этим классом, который имеет несколько статических констант:
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";
}
}
Однако, когда я компилирую, я получаю ошибку constant expression required
для каждой из трех меток case.
Я понимаю, что компилятору нужно, чтобы во время компиляции было известно, что компилятор должен быть скомпилирован, но почему нет Foo.BA_
constant?
Ответы
Ответ 1
Я понимаю, что для компиляции переключателя нужно, чтобы выражение было известно во время компиляции, но почему не константа 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
, но это приводит к еще нескольким ограничениям:
1 - The constant expression restrictions can be summarized as follows. Constant expressions a) can use primitive types and [TG49] only, b) allow primaries that are literals (apart from [TG410]) and constant variables only, c) allow constant expressions possibly parenthesised as subexpressions, d) allow operators except for assignment operators, [TG411], [TG412] or [TG413], and e) allow type casts to primitive types or [TG414] only.
Note that this does not include any form of method or lambda calls, [TG415], [TG416]. [TG417] or array subscripting. Furthermore, any use of array values, [TG418] values, values of primitive wrapper types, boxing and unboxing are all excluded because of a).
Ответ 2
Вы получаете константное выражение, потому что вы оставили значения вне своих констант. Попробуйте:
public abstract class Foo {
...
public static final int BAR=0;
public static final int BAZ=1;
public static final int BAM=2;
...
}
Ответ 3
Я получил эту ошибку на Android, и мое решение было просто использовать:
public static final int TAKE_PICTURE = 1;
вместо
public static int TAKE_PICTURE = 1;
Ответ 4
Потому что это не константы времени компиляции. Рассмотрим следующий допустимый код:
public static final int BAR = new Random().nextInt();
Во время выполнения вы можете знать значение BAR
.
Ответ 5
Вы можете использовать перечисление, как в этом примере:
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 с перечислением
Ответ 6
Это было отвечено много лет назад и, вероятно, не имеет значения, но на всякий случай. Когда я столкнулся с этой проблемой, я просто использовал оператор if
вместо switch
, он решил ошибку. Это, конечно, обходной путь и, вероятно, не "правильное" решение, но в моем случае этого было достаточно.
Ответ 7
Иногда переменная 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
//...
}
Ответ 8
Получил эту ошибку в 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:
}
Ответ 9
В моем случае я получал это исключение, потому что
switch (tipoWebServ) {
case VariablesKmDialog.OBTENER_KM:
resultObtenerKm(result);
break;
case var.MODIFICAR_KM:
resultModificarKm(result);
break;
}
во втором случае я вызывал константу из экземпляра var.MODIFICAR_KM:
но я должен использовать VariablesKmDialog.OBTENER_KM
непосредственно из класса.
Ответ 10
Если вы используете его в случае переключателя, вам нужно получить тип перечисления еще до того, как вы включите это значение в переключатель. Например:
SomeEnum someEnum = SomeEnum.values()[1];
switch (someEnum) {
case GRAPES:
case BANANA: ...
И перечисление выглядит так:
public enum SomeEnum {
GRAPES("Grapes", 0),
BANANA("Banana", 1),
private String typeName;
private int typeId;
SomeEnum(String typeName, int typeId){
this.typeName = typeName;
this.typeId = typeId;
}
}
Ответ 11
Код ниже говорит само за себя,
Мы можем использовать enum с регистром switch:
/**
*
*/
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 (ClassNames.valueOf(clazz.getSimpleName())) {
case STRING:
String castValue = (String) keyValue;
break;
case BOOLEAN:
break;
case Integer:
break;
case LONG:
break;
default:
isValid = false;
}
Надеюсь, это поможет :)
Ответ 12
Я рекомендую использовать перечисления:)
Проверьте это:
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());