Enum em bloco switch/case

Pessoal…

Brincando um pouco com o enum e switch quando codificava, me deparei com o seguinte erro, que não entendi o que exatamente ocorre.

enum a {A,B,C}
public class TesteEnumSwitch {
	public static void main(String[] args) {
		Teste teste = new Teste();
		a teste2 = a.B;
		switch (teste.atrEnum) {
		case A:
			break;
		case B:
			break;
		case C:
			break;
		default:
			break;
		}
	}

}

class Teste{
	a atrEnum = a.B; 
}

Neste código acima, a classe compila sem nenhum problema, tudo OK… No entanto, quando eu altero as constantes de case, como no exemplo abaixo, ocorre o erro.

enum a {A,B,C}
public class TesteEnumSwitch {
	public static void main(String[] args) {
		Teste teste = new Teste();
		a teste2 = a.B;
		switch (teste.atrEnum) {
		case a.A:
			break;
		case a.B:
			break;
		case a.C:
			break;
		default:
			break;
		}
	}

}

class Teste{
	a atrEnum = a.B; 
}

[color=red]The enum constant a.A reference cannot be qualified in a case label[/color]

Esse erro tem alguma coisa com a regra de que o case deve conhecer o valor da variável em tempo de compilação ou é outra regra que está criando este erro?

Valeu pessoal! :slight_smile:

É exatamente o que o erro diz. Você não deve qualificar as constantes do enum com o nome do enum durante o switch.
Ou seja, fazer a.A é errado pela definição da linguagem. O correto seria só A mesmo.

Mas… na prática, melhor ainda é usar o polimorfismo e não fazer o switch, como descrito aqui:
http://www.guj.com.br/posts/list/55885.java#293436

A questão não é a melhor prática ou não, o código postado é um código simples e somente utilizado para efeitos de visualização do problema…

Quanto ver que utilizar a.A é errado, isso eu pude constantar… Mas o que eu quero saber é porque isso é errado…
ViniGodoy, tu sabe em qual documento está escrito isso que tu me informou?

Valeu, abraços!

O por que a norma não explica. Segundo a gramática do comando switch:

[code]SwitchLabel:
case ConstantExpression :
case EnumConstantName :
default :

EnumConstantName:
Identifier[/code]

Ou seja, só as constantes do enum (os identificadores) devem entrar no switch.

O “Porquê” é relativamente simples. O “switch” tem sempre de compilar para a instrução “tableswitch” ou “lookupswitch”, que só trabalham com pequenas tabelas de inteiros e labels. Ou seja, seu código é transformado pelo compilador para:

enum a {A,B,C}
public class TesteEnumSwitch {
	public static void main(String[] args) {
		Teste teste = new Teste();
		a teste2 = a.B;
		switch (teste.atrEnum.ordinal()) {
		case 0:
			break;
		case 1:
			break;
		case 2:
			break;
		default:
			break;
		}
	}

}

class Teste{
	a atrEnum = a.B; 
}

Só que para poder determinar, em tempo de compilação, os valores corretos dos ordinais (A = 0, B = 1, C = 2 etc.) só há um jeito, que é o de ter a enum visível no mesmo arquivo .java, tal como você fez aí. Se ele estiver em um outro arquivo .java, pode ser que os valores possam ser alterados de uma compilação para outra.

O pessoal que definiu a linguagem então deu um passo adiante: já que todas as constantes têm de ser do mesmo tipo (no seu caso, “enum a”, que tal eliminar a redundância e evitar que você possa usar uma outra enum? (como você sabe, todas as enums são incompatíveis entre si, já que uma enum não pode herdar de ouotra enum).

É por isso que você não pode especificar o nome da enum na constante, no caso de switch e case.

1 curtida