регистр последней переменной в операторе switch

        final int a = 1;
        final int b;
        b = 2;
        final int x = 0;

        switch (x) {
            case a:break;     // ok
            case b:break;     // compiler error: Constant expression required

        }
        /* COMPILER RESULT:
                constant expression required
                case b:break;
                     ^
                1 error
        */

Почему я получаю такую ​​ошибку? Если бы я сделал final int b = 2, все работает.


person Furlando    schedule 27.04.2013    source источник
comment
определение как final int b; сделает его переменной.   -  person Roman C    schedule 27.04.2013
comment
таким образом, прежде чем вы его запустите, он имеет нулевое значение   -  person Roman C    schedule 27.04.2013
comment
и, наконец, он инициализирован, почему это выражение переключения, которое не принимает переменные?   -  person Roman C    schedule 27.04.2013
comment
используя переключатель, эквивалентный if-else, это не очень хорошее использование карты, вместо этого он принимает любой объект в качестве ключа.   -  person Roman C    schedule 27.04.2013
comment
Роман, о чем ты? :)   -  person Furlando    schedule 27.04.2013
comment
@RomanC вы уверены, что комментируете правильный вопрос? Просто спрашиваю.   -  person Pshemo    schedule 27.04.2013
comment
@RomanC Ошибки компиляции являются частью вопроса ...   -  person maba    schedule 27.04.2013


Ответы (3)


b может быть не инициализирован, и ему может быть присвоено несколько значений. В вашем примере он явно инициализирован, но, вероятно, компилятор этого не знает (и не может). Представить:

final int b;
if (something) {
   b = 1;
} else {
   b = 2;
}

Компилятору нужна константа в switch, но значение b зависит от какой-то внешней переменной.

person Bozho    schedule 27.04.2013
comment
Но не мог ли компилятор увидеть, что я инициализировал его в следующей строке (после объявления), поэтому ему не следует беспокоиться о том, что он инициализирован где-то еще? - person Furlando; 27.04.2013
comment
@Furlando нет, компилятор не может этого сделать. Представьте, что вместо этого предложения if вы используете сложный метод, который извлекает значение из базы данных или другого внешнего источника. - person Luiggi Mendoza; 27.04.2013
comment
@Furlando После создания final int a = 1; и использования его как x=3*a*a компилятор оптимизирует ваш код и заменит a на 1 в вашем байтовом коде, поэтому вы можете использовать его в case a:break;, но поскольку b может быть объявлено позже, как final int a = new Random().nextInt(), компилятор не сможет предсказать, что b будет и не сможет заменить его на какую-то константу, которая требуется для параметра case, поэтому вы видите свою ошибку. - person Pshemo; 27.04.2013
comment
@Pshemo Спасибо за это хорошее объяснение! - person Furlando; 27.04.2013
comment
Я думаю, что этот ответ немного неверен (cc: @Furlando), потому что компилятор Java наверняка увидит, что переменная точно инициализирована. Если вы попытаетесь использовать переменную, когда компилятор не может быть на 100% уверен, что она была инициализирована, вы получите ошибку компилятора. Однако он не выполняет аналогичный анализ потока кода для значения, поэтому он будет рассматривать final как константу (разрешено в case), только если оно инициализировано в операторе объявления. - person hyde; 28.04.2013
comment
Это в основном то, что я имел в виду. Я наверное не так ясно выразился? - person Bozho; 28.04.2013
comment
@Божо Ну, ваш ответ начинается с b, возможно, он не был инициализирован ... так что да, возможно, немного переформулируйте его. Компилятор действительно знает, будет ли b обязательно инициализировано или нет, когда он используется. - person hyde; 28.04.2013
comment
хм, это не так. Что, если есть if(что-то) {b = ...}. Затем в переключателе компилятор не знает, инициализирован ли b. И потому что, если это не может быть встроено. - person Bozho; 30.04.2013
comment
@Bozho Если есть путь кода, который может оставить переменную local неинициализированной до того, как ее значение будет использовано (где угодно, а не только в регистре переключения), вы получите ошибку компилятора. Попробуйте... Проблема вопроса заключается в разнице между инициализацией времени компиляции (final int I=1;) и времени выполнения (final int I; I=1;) переменной final, а не в неопределенности инициализации перед использованием. - person hyde; 01.05.2013
comment
ну да, но я думаю, что это одно и то же. Последний не может быть инициализирован во время компиляции, потому что компилятор не уверен :) - person Bozho; 07.05.2013
comment
@Божо, чтобы прояснить разницу, рассмотрим следующее: final int b = something ? 1 : 2; Таким образом, значение b по-прежнему зависит от времени выполнения. Будет ли это разрешено? - person Chris Betti; 13.02.2014
comment
@Божо, Фурландо просит оператор Switch ... ваше решение говорит об операторе if-else !! - person CoDe; 17.02.2016

Регистр в операторах switch должен быть постоянным на времени компиляции. Команда

final int b=2

присваивает значение 2 b прямо во время компиляции. Но следующая команда присваивает значение 2 b в Во время выполнения.

final int b;
b = 2;

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

person Rahul Bobhate    schedule 27.04.2013
comment
Так что я могу сделать вместо этого? - person starbeamrainbowlabs; 08.02.2018

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

Чтобы сделать это, компилятор Java запускает анализ потока, чтобы гарантировать, что для каждого присвоения пустой конечной переменной переменная определенно не назначена до назначения; в противном случае возникает ошибка времени компиляции

Вот почему, когда компилятор компилирует конструкцию switch, он выдает требуемое постоянное выражение, поскольку значение b неизвестно компилятору.

person rozar    schedule 27.04.2013