Duvida enum e generics

11 respostas
Marques

Colegas,
No meu sistema tem varios enums e para cada um deles eu preciso fazer mais ou menos o que se vai na classe abaixo onde deixei apenas o basico para vc entender o meu problema que eh o seguinte:
Para cada um dos enums eu preciso executar o mesmo codigo. Entaum eu pensei em criar um metodo como o asSelectItem passando como parametro o enum (que pode ser qualquer um do sistema e esse metodo vai gerar uma lista para mim.
Porem naum estou conseguindo. Vc pode me ajudar?
PS: Sei que assinatura do metodo asSelectItem naum deve estar correta.

package br.com.fit.teste;

import br.com.fit.enums.InsumoFormaAplicacaoUvaEnum;

public class Teste {

	private static void asSelectItem(Enum<?> meuEnum) {
		
		
		for (meuEnum.getClass().getSimpleName() meu : meuEnum) {
			//System.out.printl(Gostaria de imprimir aqui o mesmo que eu imprimo mo main)
			//
		}
	}

	public static void main(String[] args) {
		//esse for funciona
		for (InsumoFormaAplicacaoUvaEnum m : InsumoFormaAplicacaoUvaEnum.values()) {
			System.out.println(m.getId() + " >> " + m.toString());
		}
		//Não estou conseguindo chamar o método asSelectItem para substituir esse for que eu faço para cada enum
		// asSelectItem(InsumoFormaAplicacaoUvaEnum);
	}

}

11 Respostas

M

Você quer imprimir os valores de todos as constantes dentro de um Enum? É isso mesmo?

Você poderia criar um Interface que defina o método getId() (por exemplo, Identificavel) e fazer com que seus Enums implementem essa interface.

Depois, no método poderia fazer algo como:

public static void main(String[] args) throws Exception {                   
	// tanto MeuEnum1 como MeuEnum2 implementam Identificavel               
	imprimeIds(MeuEnum1.class);                                             
	imprimeIds(MeuEnum2.class);                                             
}                                                                           
                                                                            
/**                                                                         
 * Imprime todos os IDs dos objetos dentro do enum especificado.            
 *                                                                          
 * @param c                                                                 
 *            a classe do enum (resgatada por MeuEnum.class).               
 */                                                                         
public static void imprimeIds(                                              
		Class<? extends Enum<? extends Identificavel>> c) throws Exception {
	Method m = c.getMethod("values", (Class<?>[]) null);                    
	Enum<?>[] r = (Enum<?>[]) m.invoke(null, (Object[]) null);              
	for (Enum<?> t : r) {                                                   
		Identificavel a = (Identificavel) t;                                
		System.out.println(a.getId());                                      
	}                                                                       
}
Marques

vlw marcobiscaro2112 !!!

Era isso mesmo!
Obrigadaum!

ViniGodoy

Não é mais fácil usar o values() diretamente???

for (Identificavel a : seuEnum.values()) { System.out.println(a.getId()); }

Sempre que puder, não use reflexão!

M

Mas nesse caso Vini, trataríamos apenas de um enum por vez (eu sei que são só 3 linhas, mas imagine criar um método desse para cada enum que houver na aplicação e distinguí-lo na hora de chamar).

E seria necessário mesmo criar um método para cada enum (um para MeuEnum, outro para SeuEnum, mais um para NossoEnum e assim por diante) por que a classe Enum simplesmente não declara o método values() (ele “brota” ao se declarar um enum).

Logo o único jeito de acessar o método values() de qualquer enum é via reflection certo? Ou viajei completamente?

ViniGodoy

Já elaboro um exemplo. Deixa só eu baixar o Java e o Netbeans aqui.

ViniGodoy
Passo 1: Criar uma interface com o método em comum:
public interface Identificavel {
    int getId();
}

Passo 2: Fazer as enumerações desejadas implementa-las:

public enum Enum1 implements Identificavel {
    VALOR1(1),
    VALOR2(2);

    private int id;

    private Enum1(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }
}
public enum Enum2 implements Identificavel {
    VALOR3(3),
    VALOR4(4);

    private int id;

    private Enum2(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }
}
Passo 3: Listar os valores
import java.util.Arrays;
import java.util.Collection;

public class Main {
    public static void listaValores(Collection<? extends Identificavel> valores)
    {
        for (Identificavel valor : valores) {
            System.out.println("Id:" + valor.getId());
        }
    }

    public static void main(String[] args) {
        listaValores(Arrays.asList(Enum1.values()));
        listaValores(Arrays.asList(Enum2.values()));
    }
}

Eu faria assim. Evita reflection (o que mantém o código typesafe), além do método listaValores poder ser usado por outros tipos de coleções ou classes (além do enum). Fora que o código fica absurdamente mais simples. :)

M

Collection… é verdade. Por que as pessoas tendem a fazer a coisa da maneira mais difícil?

Boa ViniGodoy. Bom, ao menos fica um exemplo de reflection a mais aqui no fórum. :slight_smile:

Agora, você sabe onde o método values() é definido? Ou ele não é? Ou é somente implicitamente?

ViniGodoy

Se eu não me engano ele é gerado implicitamente pelo enum. Fica definido na classe do enum, como um método estático.

Na verdade, o enum é um sintax suggar que implementa o typesafe enum pattern, descrito no livro Effective Java, de maneira automática. E de quebra, fornece alguns métodos úteis. Para ver a cara do enum, antes do Java 5, veja:
http://java.sun.com/developer/Books/effectivejava/Chapter5.pdf (página 8 do pdf, item 21, replace enum with classes)
http://www.javacamp.org/designPattern/enum.html

sergiotaborda

ViniGodoy:
Se eu não me engano ele é gerado implicitamente pelo enum. Fica definido na classe do enum, como um método estático.

Na verdade, o enum é um sintax suggar que implementa o typesafe enum pattern,

Cuidado. enum não é sintax sugar. implica em mecanismos especiais para carregamento de classes da JVM. Lembrar que todos os enum são serializable e que o fato de declarar public enum em vez de public class XPTO extends Enum se deve a um problema lógico entre a serilização e a subclasse.
Embora todos os enum sejam realmente filhos da classe Enum isso é feito com ajuda da JVM e portanto não pode ser considerado sintax sugar (que é quando o compilador faz todo o trabalho)

ViniGodoy

sergiotaborda:
Cuidado. enum não é sintax sugar. implica em mecanismos especiais para carregamento de classes da JVM. Lembrar que todos os enum são serializable e que o fato de declarar public enum em vez de public class XPTO extends Enum se deve a um problema lógico entre a serilização e a subclasse.
Embora todos os enum sejam realmente filhos da classe Enum isso é feito com ajuda da JVM e portanto não pode ser considerado sintax sugar (que é quando o compilador faz todo o trabalho)

Interessante, o tutorial da sun diz que é o compilador:

Você tem alguma referência que diga que o enum é uma construção da VM? Nunca pesquisei muito sobre o assembly java em si, e seria interessante descobrir que isso não é só um syntax suggar, e ver como eles fizeram para que um enum do Java 5 funcione no Java 4.

sergiotaborda

ViniGodoy:
sergiotaborda:
Cuidado. enum não é sintax sugar. implica em mecanismos especiais para carregamento de classes da JVM. Lembrar que todos os enum são serializable e que o fato de declarar public enum em vez de public class XPTO extends Enum se deve a um problema lógico entre a serilização e a subclasse.
Embora todos os enum sejam realmente filhos da classe Enum isso é feito com ajuda da JVM e portanto não pode ser considerado sintax sugar (que é quando o compilador faz todo o trabalho)

Interessante, o tutorial da sun diz que é o compilador:

Você tem alguma referência que diga que o enum é uma construção da VM? Nunca pesquisei muito sobre o assembly java em si, e seria interessante descobrir que isso não é só um syntax suggar, e ver como eles fizeram para que um enum do Java 5 funcione no Java 4.

O compilador cria os métodos estáticos, mas o mecanismo de enums é suportado pelo compilador + jvm.

Da especificação da linguagem

“It is a compile-time error to attempt to explicitly instantiate an enum type (§15.9.1). The final clone method in Enum ensures that enum constants can never be cloned, and the special treatment by the serialization mechanism ensures that duplicate instances are never created as a result of deserialization. Reflective instantiation of enum types is prohibited. Together, these four things ensure that no instances of an enum type exist beyond those defined by the enum constants.”
in http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.9 enfase meu

Se fosse sintaxe sugar funcionaria no 1.4 ( aka for-each)
enums não é como genérics. Não é possivel fazer corretamente sem a ajuda da jvm. Com as ferramentas do 1.4 dá para fazer algo semelhante mas que tem problemas sobretudo com serialização e garbage - várias instancias iguais à toa - o que aconteceria tb se houvesse acesso via refelction . Essa foi a maior razão para incluir isso no java 5.

As instancias do enum são o mais proximo que ha de um singleton em java e é a forma mais segura de criar um hoje em dia (Effective java 2º edição para mais detalhes)

Criado 21 de dezembro de 2009
Ultima resposta 22 de dez. de 2009
Respostas 11
Participantes 4