Galera, rolou uma dúvida aqui quando estava desenvolvendo no android mas a dúvida é no switch do java.
Suponhamos que tenha uma classe Teste e outra classe Teste2 que estende a Teste. Seguem as classes abaixo:
package br;
public class Teste {
protected final int BLA = 1;
}
package br;
public class Teste2 extends Teste {
public void testa(int id){
switch (id) {
case BLA:
// faz algo
break;
default:
// outro algo
}
}
}
Do jeito que está aí o compilador irá reclamar que a variável do case precisa ser uma constante. Caso eu adicione na variável BLA o atributo ‘static’ irá compilar sem problemas.
A pergunta é: Existe alguma maneira de, caso a variável BLA não seja static, em algum momento durante a execução modificar essa variável? Pois se não houver, acredito que esse erro seria desnecessário.
Os valores que um “case” em um “switch” aceita devem obrigatoriamente ser constantes. Portanto, você não pode fazer o que você quer desse jeito; é preciso usar o velho e bom if no seu caso.
Sim, eu sei que o valor precisa ser constante. O problema é: porque é preciso utilizar o atributo ‘static’ dentro da variável ‘BLA’ para que ela se torne uma constante se não há como modificar ela em tempo de execução.
Explicando em forma de código:
package br;
public class Teste2 {
final int BLA = 1;
public void testa(int id){
switch (id) {
case BLA:
// faz algo
break;
default:
// outro algo
}
}
}
Neste exemplo, a variável BLA é uma constante, está sem o atributo ‘static’ e compila sem problemas.
class ClasseTeste {
public static void main(String[] guj) {
final int a = 2;
int x = 1;
switch(x){
case a:
break;
}
}
}
e assim não
class ClasseTeste {
public static void main(String[] guj) {
final int a;
a = 2;
int x = 1;
switch(x){
case a:
break;
}
}
}
isso só ocorre porque o compilador java, considera que cada linha é uma ação, então, se você fizer “final int a;” o compilador considera que o valor dessa variável será conhecido somente em tempo de execução,
e, no case tem que ser uma “constant expression”, ou seja, ser conhecida antes do tempo de execução.
já quando você faz “final int a = 2;” o compilador entende que esse valor não será alterado e considera essa “variável” como uma “constant expression”.
já o código abaixo funciona pois ele não requer nenhuma “constant expression”, então ele não reclama de você fazer isso.
class ClasseTeste {
public static void main(String[] guj) {
final int a;
a = 2;
int x = 1;
System.out.println(a);
}
}
Esta explicação acima descreve o problema da variável final não ser declarada, ou o chamado ‘blank final variable’. Realmente, nesse caso, é perfeitamente possível você alterar o valor da variável em tempo de execução. Acho que vocês não entederam a minha dúvida… Bom, de qualquer forma, irei averiguar melhor essa questão.
Obrigado.
“final” é um pouco diferente de uma constante. Dizer que uma variável é “final” indica apenas que a partir de sua primeira atribuição (que pode ser feita na declaração, na passagem de parâmetros ou em uma atribuição algumas linhas depois da declaração) você não pode mudar o valor dela. Entretanto, o switch precisa de um valor realmente constante. No caso de um valor “static final”, a única forma de inicializar esse valor é realmente na sua declaração, por isso o switch pode usar esse valor que é realmente constante.
Mas o switch aceita qualquer uma das declarações. No caso do código abaixo:
package br;
public class Teste2 {
static final int BLA = 1;
public void testa(int id){
switch (id) {
case BLA:
// faz algo
break;
default:
// outro algo
}
}
}
Caso eu remova o atributo ‘static’ da variável ‘BLA’, continuará compilando normalmente. O único caso em que essa diretiva é falsa será quando a variável estiver em uma classe diferente, como foi mostrado no primeiro post. Essa que é a questão.
Quando em outra classe a variável está definida como “public static final” (ou como “static final” se estiver no mesmo pacote), o próprio valor dessa constante (se for um tipo primitivo) é exportado no .class da outra classe (lembre-se, o compilador não examina todos os fontes de uma vez; ele examina um fonte apenas de cada vez, e para referenciar as outras classes, examina os .class ou .jar contendo .class).
Quando você simplesmente escreve “final int x = 1”, o valor dessa variável final não é exportado, e portanto o compilador não consegue saber qual é o valor da constante, para usá-la no switch.
Resumindo, ao compilar a classe que usa um “public static final” definido em uma outra classe, o compilador simplesmente substitui o valor dessa constante porque ela está definida no .class da classe importada; se for um “public final”, sem static, o compilador não consegue obter o valor (porque ele não foi exportado) e é por isso que ele não consegue usar no switch.
Hmmm. Agora sim, não sabia que o compilador não exportava os valores de variáveis do tipo final. Muto obrigado, entanglement. Darei uma olhada melhor no comportamento do compilador do Java.