Entendendo o escopo da variável
Você aprendeu que as variáveis locais são declaradas em um método. Quantas variáveis locais você vê neste exemplo?
public void eat(int piecesOfCheese) {
int bitesOfCheese = 1;
}
Existem duas variáveis locais neste método. A variável bitesOfCheese é declarada dentro do método e piecesOfCheese é chamado como parâmetro do método. Também é local para o método. Ambas variáveis são têm um escopo local para o método. Isso significa que elas não podem ser usadas fora do método.
Variáveis locais nunca podem ter um escopo maior do que o método em que são definidas. No entanto, eles podem ter um escopo menor. Considere este exemplo:
3: public void eatIfHungry(boolean hungry) {
4: if (hungry) {
5: int bitesOfCheese = 1;
6: } // bitesOfCheese goes out of scope here
7: System.out.println(bitesOfCheese);// DOES NOT COMPILE
8: }
A variável hungry tem um escopo em todo o método. A bitesOfCheese tem um escopo menor. Está disponível apenas para uso na declaração if porque é declarada dentro dele. Quando você vê um conjunto de chaves ({}) no código, significa que você digitou um novo bloco de código. Cada bloco de código tem seu próprio escopo. Quando há vários blocos, você os combina de dentro para fora. No nosso caso, o bloco if começa na linha 4 e termina na linha 6. O bloco do método começa na linha 3 e termina na linha 8.
Como a bitesOfCheese é declarada nesse bloco, o escopo é limitado a esse bloco. Quando o compilador chega à linha 7, ele reclama que não sabe nada sobre essa bitesOfCheese e dá um erro:
bitesOfCheese cannot be resolved to a variable
Lembre-se de que os blocos podem conter outros blocos. Esses blocos contidos menores podem ter variáveis de referência definidas nos blocos maiores com escopo definido, mas não vice-versa. Por exemplo:
16: public void eatIfHungry(boolean hungry) {
17: if (hungry) {
18: int bitesOfCheese = 1;
19: {
20: boolean teenyBit = true;
21: System.out.println(bitesOfCheese);
22: }
23: }
24: System.out.println(teenyBit); // DOES NOT COMPILE
25: }
A variável definida na linha 18 está no escopo até que o bloco termine na linha 23. Usando isso no bloco menor das linhas 19 a 22. A variável definida na linha 20 sai do escopo na linha 22. Não é permitido usá-la na linha 24.
O exame pode tentar enganá-lo com perguntas sobre o escopo. Você provavelmente verá uma pergunta que parece ser sobre algo complexo e não consegue compilar porque uma das variáveis está fora do escopo. Vamos tentar um. Não se preocupe se você não estiver familiarizado com instruções if ou loops while ainda. Não importa o que o código faz desde que estamos falando de escopo. Veja se você pode descobrir em qual linha cada uma das cinco variáveis locais entram e saem do escopo:
11: public void eatMore(boolean hungry, int amountOfFood) {
12: int roomInBelly = 5;
13: if (hungry) {
14: boolean timeToEat = true;
15: while (amountOfFood > 0) {
16: int amountEaten = 2;
17: roomInBelly = roomInBelly - amountEaten;
18: amountOfFood = amountOfFood - amountEaten;
19: }
20: }
21: System.out.println(amountOfFood);
22: }
O primeiro passo para definir o escopo é identificar os blocos de código. Neste caso, são três blocos. Você pode dizer isso porque existem três conjuntos de chaves ({}). Começando do conjunto interno, podemos ver onde o bloco do loop while começa e termina. Repita isso para sair do bloco de instrução if para o bloco do método. A Tabela 1.3 mostra os números de linha em que cada bloco começa e termina.
Você vai querer praticar muito essa habilidade. Identificar blocos precisa ser uma segunda natureza para o exame. A boa notícia é que há muitos exemplos de código para praticar. Você pode ver qualquer exemplo de código neste livro sobre qualquer assunto e verificar as chaves.
Agora que sabemos onde estão os blocos, podemos examinar o escopo de cada variável. hungry e amountOfFood são parâmetros de método, então eles estão disponíveis para todo o método. Isso significa que seu escopo é das linhas 11 a 22. roomInBelly entra no escopo na linha 12 onde é declarada. Permanece no escopo pelo resto do método e sai do escopo na linha 22. timeToEat entra no escopo na linha 14 onde é declarada. Sai do escopo na linha 20, onde o bloco if termina. amountEaten entra no escopo na linha 16 onde é declarado. Ela sai do escopo na linha 19, onde o bloco while termina.
Tudo isso foi para variáveis locais. Felizmente, a regra para variáveis de instância é mais fácil: elas estarão disponíveis assim que forem definidas e duram toda a vida útil do próprio objeto. A regra para variáveis de classe (static) é ainda mais fácil: elas entram em escopo quando declaradas como os outros tipos de variáveis. No entanto, eles permanecem no escopo por toda a vida do programa.
Vamos fazer mais um exemplo para se certificar de que você tem um controle sobre isso. Mais uma vez, tente imaginar o tipo das quatro variáveis e quando elas entram e saem do escopo.
1: public class Mouse {
2: static int MAX_LENGTH = 5;
3: int length;
4: public void grow(int inches) {
5: if (length < MAX_LENGTH) {
6: int newSize = length + inches;
7: length = newSize;
8: }
9: }
10: }
Nesta classe, temos uma variável de classe (MAX_LENGTH), uma variável de instância (length), e duas variáveis locais (inches e newSize). MAX_LENGTH é uma variável de classe porque tem a palavra-chave static em sua declaração. MAX_LENGTH entra no escopo na linha 2, onde está declarada e permanece no escopo até o final do programa. length entra no escopo na linha 3, onde é declarado e permanece no escopo enquanto esse objeto Mouse existir. inches entra no escopo onde é declarado na linha 4 e sai do escopo no final do método na linha 9. newSize entra no escopo onde é declarado na linha 6 dentro do bloco if e sai do escopo quando esse bloco termina na linha 8.
Aprendeu tudo isso? Vamos rever as regras sobre o escopo:
■ Variáveis locais - no escopo da declaração ao final do bloco
■ Variáveis de instância - no escopo da declaração até que o lixo do objeto seja coletado
■ Variáveis de classe - no escopo da declaração até o final do programa