Dúvida em enum

Estou estudando pelo livro de Kathy para tirar a SCJP.

Vendo esse cídogo fiquei meio atrapalhado.

enum Animals {
	DOG("Woof"), CAT("Meow"), FISH("Burble");
	
	String sound;
	
	Animals(String s) {
		sound = s;
	}
	
}

class TestEnum{
	static Animals a = Animals.DOG;
	
	public static void main(String[] args) {
		System.out.println(a.DOG.sound +" " +a.FISH.sound);
	}
	
}

Ele dá como saída: Woof Burble

A minha dúvida é a seguinte:

A varíavel de classe a do tipo Animals não deveria ter sido inicializada??
E mais, ele não deveria conter somente uma constante do enum, pelo que vi ela tem todo o enum, por ela eu obtenho todas as constantes do enum.

Normalmente quando uso um enum faço mais ou menos assim:

public class Teste{
	
	public static enum EnumTeste{TESTE1, TESTE2, TESTE3};
	
	public static void metodoTeste(EnumTeste enumTeste){
		if (enumTeste == EnumTeste.TESTE1){
			System.out.println("TESTE1");
		} else if (enumTeste == EnumTeste.TESTE2){
			System.out.println("TESTE2");;
		} else if (enumTeste == EnumTeste.TESTE3){
			System.out.println("TESTE3");
		} else {
			System.out.println("NENHUM DELES");
		}
	}
	
	public static void main(String[] args){
		metodoTeste(EnumTeste.TESTE1);
	}
	
}

Ele imprime justamente TESTE1, porque ao escrever o seguinte código, eu consigo acessar as demais constantes do enum??? A variável enumTest não deveria ser somente uma EnumTeste.TESTE1 n???

enumTeste.TESTE2;
enumTeste.TESTE3;

Não esperava que o código acima compilasse. Alguem sabe me explicar o porquê de tudo isso? =P

A variavel está com o modificador de acesso default(sem nenhum). Coloca como private…

A variável foi inicializada.
Esta questão é recorrente e na realidade testa se vc entende o conceito de static e não o de enum.

Sendo que todas as instancias do enum são constantes estáticas da classe do enum então eu posso aceder a uma instancia do enum pelo nome da classe como em Animals.DOG ou por uma instancia dessa classe , no caso a.
Eu poderia fazer Animals.DOG.FISH.sound e obteria o som de peixe.

Vc deveria fazer :

public class Teste{
	
	public static enum EnumTeste{TESTE1, TESTE2, TESTE3};
	
	public static void metodoTeste(EnumTeste enumTeste){

                switch (enumTeste){
		case EnumTeste.TESTE1:
			System.out.println("TESTE1");
                        break;
		case EnumTeste.TESTE2:
			System.out.println("TESTE2");
                        break;
		case EnumTeste.TESTE3:
			System.out.println("TESTE3");
                        break;
		default:
			System.out.println("NENHUM DELES");
		}
	}
	
 // ou menlhor ainda

	public static void metodoTeste(EnumTeste enumTeste){

                switch (enumTeste){
		case EnumTeste.TESTE1:
		case EnumTeste.TESTE2:
		case EnumTeste.TESTE3:
			System.out.println(enumTeste.toString());
                        break;
		default:
			System.out.println("NENHUM DELES");
		}
	}
}

Hum… então acho q entendi, todas as contantes do enum são static.
Vlw kra.

Eu ia criar um tópico para postar uma dúvida sobre enum, mas vou aproveitar esse aqui.

Não estou conseguindo usar enum em switch… até mesmo esse exemplo que sergiotaborda colocou… tá dando o seguinte erro:

The enum constant Teste.EnumTeste.TESTE1 reference cannot be qualified in a case label

(na verdade, o erro está em todas as 3 constantes, não é apenas em TESTE1 não.)

Alguém sabe pq tá dando esse erro?

Experimente tirar a qualificação (usar TESTE1 em vez de Teste.EnumTeste.TESTE1).

Isso quer dizer também o seguinte: se a constante enum tiver sido criada em um outro arquivo .java (não no mesmo), não se pode usar a constante em um “switch”. Que sinistro :frowning:

entendi… agora quando fui testar vi outra coisa que nao entendi…

coloquei o codigo dessa forma:

public void metodoTeste(EnumTeste enumTeste){
		final EnumTeste enumTeste1 = EnumTeste.TESTE1;
		
        switch (enumTeste){
			case TESTE1:
			case TESTE2:
			case enumTeste1:
		}
	}

TESTE1 e TESTE2 compilam… mas dá erro em enumTeste1… diz o seguinte:

"enumTeste1 cannot be resolved or is not a field"

o que eu consegui entender foi o seguinte: quando a expressão a ser avaliada no switch é um enum, vc não precisa colocar a constante qualificada, pois o compilador já vai saber o tipo do enum e só vai permitir vc colocar no case algum valor que tenha sido definido na declaração do enum. Assim, mesmo enumTeste1 sendo uma variável do tipo do enum e estando com um valor que é uma constante válida, como não existe a constante enumTeste1, dá erro de compilação… é isso mesmo?

fazendo os testes aqui, também verifiquei que se vc declarar o enum fora de uma classe (no seu própprio .java ou dentro de um outro .java - lembrando que o enum não poderá ser public se a classe for public), você pode usar suas constantes no case… e não precisa ser qualificado justamente porque deve funcionar como eu citei acima… o compilador já sabe em qual enum procurar por causa do tipo da variável que tá na expressão do switch… então não precisamos colocar o nome qualificado por causa disso… deve ser isso mesmo correto?

É isso mesmo. Na pressa deixei o nome qualificado, mas é sem qualificação.

Para entender 100% o enum, o ideal é entender de onde partiu a idéia de se fazer um enum tão exótico assim.

Na verdade, partiu do conceito de typesafe enum pattern, explicado por Joshua Bloch, no Livro Effective Java, no item 21.

http://java.sun.com/developer/Books/effectivejava/Chapter5.pdf

O enum do Java 5, só apresenta uma sintaxe simplificada e algumas facilidades para a implementação de um enum desse tipo. Eu recomendo fortemente a leitura desse item 21.

Tópico que salvou da dúvida cruel quase 6 meses depois… Obrigado a força amigos!

sim enum fora da classe pode ser public ou default pq enum é um tipo especial de classe… e no switch nao pode ser isto:

case MinhaEnum.Carro:

isso acima é invaliado…

Olá pegando carona no tópico,
porque o Enum só aceita construtores default e private??

E se eu estiver em outro pacote, então nao vou poder criar o enum???

Att

[quote=danielbussade]Olá pegando carona no tópico,
porque o Enum só aceita construtores default e private??

E se eu estiver em outro pacote, então nao vou poder criar o enum???

Att[/quote]

Não entendi. Você testou isso que você falou? Porque pela lógica tanto faz o acesso do construtor do enum já que ele não pode ser acessado diretamente. Ou seja, você não pode dar
new nome_enum();
(mesmo o construtor do enum possuindo acesso default)
Então, seguindo essa lógica o construtor do enum pode ter qualquer modificador. (assim como qualquer construtor)

[]s
Gunnar

O case do switch não pode ser usado usando as variáveis qualificadas do enum, independente de onde o enum seja declarado.
A expressão1 do switch deve avaliar para um enum , ou para int. Quando avalia para enum só faz sentido os cases possuirem valores declarados no enum (que por sua vez também são instâncias do enum).

[]s
Gunnar

Olá gunnar eu testei sim, e ele não aceita o modificador public. Mas mesmo eu colocando como private eu consigo acessar. Agora que fui entender, eu não preciso instanciar porque as constantes do enum são todas estáticas ou seja, já estão instanciadas!
Ai me surgiu outra dúvida, se tanto faz eu colocar default ou private, de qualquer jeito eu não vou poder dar new, então qual a diferença???

Att

[quote=danielbussade] Olá gunnar eu testei sim, e ele não aceita o modificador public. Mas mesmo eu colocando como private eu consigo acessar. Agora que fui entender, eu não preciso instanciar porque as constantes do enum são todas estáticas ou seja, já estão instanciadas!
Ai me surgiu outra dúvida, se tanto faz eu colocar default ou private, de qualquer jeito eu não vou poder dar new, então qual a diferença???

Att

[/quote]

Diferença prática nenhuma. Você não pode nunca criar uma instância do enum…

XEnum x = new XEnum();//não é permitido

É curioso notar que embora não seja possível usar public, o default também permite acesso ao construtor para as classes do mesmo pacote…É possível declarar o construtor do enum como protected?

[]s
Gunnar

enum Animals {
	DOG("Woof"), CAT("Meow"), FISH("Burble");
	
	String sound;
	
	Animals(String s) {
		sound = s;
	}
	
}

class TestEnum{
	static Animals a = Animals.DOG;
	
	public static void main(String[] args) {
		System.out.println(a.DOG.sound +" " +a.FISH.sound);
	}
	
}

Reaproveitando este tópico, eu fiquei com outra dúvida…

O construtor do enum recebe uma string como argumento. Para o código funcionar, o construtor não deveria ser chamado passando-se uma string?

Obrigado,
Fernando

[quote=ferdu][code]
enum Animals {
DOG(“Woof”), CAT(“Meow”), FISH(“Burble”);

String sound;

Animals(String s) {
	sound = s;
}

}

class TestEnum{
static Animals a = Animals.DOG;

public static void main(String[] args) {
	System.out.println(a.DOG.sound +" " +a.FISH.sound);
}

}
[/code]

Reaproveitando este tópico, eu fiquei com outra dúvida…

O construtor do enum recebe uma string como argumento. Para o código funcionar, o construtor não deveria ser chamado passando-se uma string?

Obrigado,
Fernando

[/quote]

Mas é isso o que acontece na linha:
DOG(“Woof”), CAT(“Meow”), FISH(“Burble”);

[]s
Gunnar

putz… falha nossa… :oops:

obrigado!!