Оператор Switch: требуется константное выражение, ошибка

Eclipse показывает ошибку Требуется константное выражение, но все поля имеют final. тогда почему выдает эту ошибку. Может кто-нибудь объяснить мне, где моя ошибка.

package com.oca.test.exam;

public class Test {

    public static final Integer x1 = 5;
    public static final Integer x2 = 10;
    public static final Integer x3 = 15;
    public static final Integer x4 = 20;

    public static void main(String[] args) {
        switch (x1) {
        case x1: 
            System.out.println();
            break;

        case x2: 
            System.out.println();
            break;

        case x3: 
            System.out.println();
            break;

        case x4: 
            System.out.println();
            break;
        }
    }
}

person Ng Sharma    schedule 24.02.2019    source источник
comment
Пожалуйста, не отмечайте повторяющийся вопрос. Проблема новая. - Нет.   -  person Turing85    schedule 24.02.2019
comment
Кстати: когда x1 не будет равно x1?   -  person Turing85    schedule 24.02.2019
comment
Возможный дубликат оператора Java switch: требуется постоянное выражение, но это ПОСТОЯННО   -  person Joe C    schedule 24.02.2019
comment
вариант использования 5: System.out.println(); ломать; случай 10: System.out.println(); ломать; случай 15: System.out.println(); ломать; случай 20: System.out.println(); ломать; по умолчанию: System.out.println(); ломать;   -  person javaworld    schedule 24.02.2019


Ответы (3)


TL;DR находится в конце.

Изучив документацию оператора switch, мы можем найти следующий:

Переключатель работает с примитивными типами данных byte, short, char и int. Он также работает с перечислимыми типами (обсуждаемыми в Enum Types), классом String и несколькими специальными классами, обертывающими определенные примитивные типы: Character, Byte, Short и Integer (обсуждаемые в Numbers and Strings).

Сначала это кажется нормальным, и вашей проблемы не должно существовать. Однако в определении не упоминается, где эти оболочки можно использовать, а где нет. Изучая спецификации коммутатора- операторов (JLS) мы находим, что переключатель имеет форму:

1 Switch-Expression

SwitchStatement: switch ( Expression ) SwitchBlock

Далее поясняется Expression:

Тип Expression должен быть char, byte, short, int, Character, Byte, Short, Integer, String или тип перечисления (§8.9), иначе возникает ошибка времени компиляции.

Так что здесь совершенно нормально использовать класс-оболочку, такой как Integer. Компилятор справится.

2 Switch-Block

Блок-переключатель можно разбить на:

SwitchLabels BlockStatements

SwitchLabel определяется как:

SwitchLabel: case ConstantExpression : case EnumConstantName : default :

Таким образом, метка будет принимать только константные выражения или перечисления. Если мы теперь посмотрим на определение константного выражения, мы найдем:

Константное выражение — это выражение, обозначающее значение примитивного типа или строку...

Конечно, некоторые условия должны применяться, чтобы сделать примитивный тип константой (он указан там), но в вашем случае важной частью является то, что вы должны использовать примитивный тип или строку.

БОНУС

Обмен между классом-оболочкой и примитивным типом называется "автоупаковка или распаковка" (в зависимости от направления). Согласно документации, распаковка происходит, когда:

Преобразование объекта типа-оболочки (Integer) в соответствующее значение примитива (int) называется распаковкой. Компилятор Java применяет распаковку, когда объект класса-оболочки:

  • Передается как параметр методу, который ожидает значение соответствующего примитивного типа.
  • Присваивается переменной соответствующего примитивного типа.

Таким образом, похоже, что Java просто не предназначена для выполнения необходимой распаковки, чтобы оператор switch работал, как вы предполагали.

----------------------

TL;DR

Для выражения переключения вы можете использовать класс-оболочку. Однако для меток вы можете использовать только примитивные типы: byte, short, char и int.

person Younes EO    schedule 24.02.2019

case выражения должны быть постоянными выражениями, вы можете использовать enum, это лучше для постоянных значений и более читаемого кода, вот пример для перечисления:

класс перечисления:

    public enum Numbers {

    HIGH(3), // calls constructor with value 3
    MEDIUM(2), // calls constructor with value 2
    LOW(1) // calls constructor with value 1
    ; // semicolon needed when fields / methods fol
    private final int levelCode;

    Numbers(int levelCode) {
        this.levelCode = levelCode;
    }

    public int getLevelCode() {
        return this.levelCode;
    }
}

для вас основной метод:

public class Test {

    public static void main(String[] args) {
        switch (Numbers.HIGH) {
        case HIGH:
            System.out.println("hight");
            break;

        case MEDIUM:
            System.out.println("medium");
            break;

        case LOW:
            System.out.println("low");
            break;

        }

    }
}
person yali    schedule 24.02.2019
comment
вы используете Numbers.HIGH в условии switch, но HIGH, MEDIUM и LOW в случаях. Это может привести к неприятным ошибкам. - person Turing85; 24.02.2019
comment
я знаю, но это для того, чтобы он понял, что лучше для него, он хочет использовать x1 в выражении switch, поэтому он уже хочет использовать final для постоянного значения, но switch лучше, чем final значения - person yali; 24.02.2019

Переменные, объявленные как final в Java, не считаются постоянными времени компиляции, поскольку их значения могут изменяться во время выполнения — от неопределенного состояния к определенному.

Значения случая должны быть определены на месте, например. case 5: case 12: case "green":

person SoyChai    schedule 24.02.2019
comment
случай 12.5f: тип с плавающей запятой, вы уверены.. - person Ng Sharma; 24.02.2019
comment
Вы правы, здесь допустимы только целые числа. Исправлено. - person SoyChai; 24.02.2019