крайна променлива case в команда 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

Правя игра, подобна на покемон, в която се разхождате. Това е 2d игра отгоре надолу. Въпреки това се опитвам да открия определена плочка пред себе си.

Моят герой е на Y 1, а картата на Y 0. Опитах се да препратя raycast, но не се получи.

ето какво опитах:

if (Input.GetKey("w") && isMoving == false)
        {
            bool disableMove = false;
            RaycastHit hit;
            if (Physics.Raycast(transform.position, Vector3.forward, out hit, 2))
            {
                var distanceToGround = hit.distance;
                Debug.Log("HIT");

                if (hit.collider.gameObject.tag == "collision")
                {
                    disableMove = true;
                    Debug.Log("Tree");
                }
            }
            if (!disableMove)
            {
                Calculatewalk();
                anim.Play("WalkingUp");
                increment = 0;
                isMoving = true;
                startPoint = transform.position;
                endPoint = new Vector3(transform.position.x, transform.position.y, transform.position.z + 1);
            }
            disableMove = false;
        }
- person hyde; 28.04.2013
comment
По принцип това имах предвид. Може би не го казах толкова ясно? - person Bozho; 28.04.2013
comment
@Bozho Добре, отговорът ти започва с b може да не е инициализиран... така че да, може би го преформулирайте малко. Компилаторът знае дали b със сигурност ще бъде инициализирано или не, когато се използва. - person hyde; 28.04.2013
comment
хм, не става. Ами ако има ако (нещо) {b = ...}. Тогава в превключвателя компилаторът не знае дали b е инициализирано. И защото ако това не може да го вгради. - person Bozho; 30.04.2013
comment
@Bozho Ако има кодова пътека, която може да остави локална променлива неинициализирана, преди стойността й да бъде използвана (навсякъде, не само с превключване на регистър), получавате грешка на компилатора. Опитайте... Проблемът на въпроса е разликата между инициализацията по време на компилиране (final int I=1;) и времето на изпълнение (final int I; I=1;) на променлива final, а не несигурността на инициализацията преди употреба. - person hyde; 01.05.2013
comment
добре, да, но мисля, че и двете са едно и също нещо. Последният не може да бъде инициализиран по време на компилация, защото компилаторът е несигурен :) - person Bozho; 07.05.2013
comment
@Bozho, за да изясниш разликата, помисли за това: final int b = something? 12; Така че стойността на b все още зависи от времето на изпълнение. Това ще бъде ли разрешено? - person Chris Betti; 13.02.2014
comment
@Bozho, Furlando иска оператор 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 изпълнява анализ на потока, за да гарантира, че за всяко присвояване на празна крайна променлива, променливата определено не е присвоена преди присвояването; в противен случай възниква грешка по време на компилиране

Ето защо, когато компилаторът компилира конструкцията за превключване, той хвърля изискван константен израз, тъй като стойността на b е неизвестна на компилатора.

person rozar    schedule 27.04.2013