Declaración de Enumeraciones en Java

Buenas noches, en esta entrada veremos por encima algo más sobre las Enumeraciones en Java, mas en profundidad que el vistazo por encima que le echamos en entradas posteriores, y sin embargo entraremos mas en profundidad mas adelante.


Como en la versión 5.0, java permite restringir una variable a tener unos valores predefinidos, en otras palabras, un valor de una lista enumerada.

Usar enum puede ayudar a reducir bugs en el código. Por ejemplo, en una aplicación de una tienda de café podemos querer tener restringido la selección de tamaños a BIG, HUGE y OVERWHELMING. Con la siguiente declaración simple, podemos garantizar que el compilador nos detendrá cuando asignemos un valor distinto a CofeeSize excepto BIG, HUGE, OVERWHELMING:

		enum CoffeeSize{ BIG, HUGE, OVERWHELMING ];
		

Con esto, la única manera de conseguir un CoffeeSize será con una sentencia como esta:

		CoffeeSize cs = CoffeeSize.BIG;
		

No se requiere que las constantes del enum estén en mayúsculas, pero en las convenciones de código de Sun las constantes están nombradas en mayúsculas, por tanto no es mala idea.

Los componentes básicos de una enum son sus constantes, aunque ahora veremos qe pueden existir muchas mas cosas en una enum. Las enumeraciones pueden ser declaradas como una clase propia separada, o como un miembro de una clase, sin embargo no deben ser declaradas dentro de un método.

Declarando un enum fuera de la clase:

		enum CoffeeSize {
			BIG,
			HUGE,
			OVERWHELMING
		}
		
		class Coffee{
			CoffeeSize size;
		}
		
		public class CoffeeTest {
			
			public static void main (String[] args){
				Coffee drink = new Coffee();
				drink.size = CoffeeSize.BIG; //Enumeración fuera de la clase
			}
		}
		

El código anterior es parte de un archivo simple. (recordamos, el archivo se debe llamar CoffeeTest.java como el nombre de la clase public). El punto clave es recardar que una enum que no está encerrado en una clase puede ser declarado solo con el modificador public o default. Aquí hay un ejemplo de una declaración de una enum dentro de una clase:

		class Coffee2{
			enum CoffeeSize {BIG,HUGE,OVERWHELMING}
			CoffeeSize size;
		}
		
		public class CoffeeTest2 {
		
			public static void main(String[] args) {
				Coffee2 drink = new Coffee2();
				drink.size = Coffee2.CoffeeSize.BIG; //Se necesita el nombre de la clase que 
													// la encierra
			}
		
		}
		

Los puntos clave que hay que mantener a distancia respecto a estos ejemplos es que las enum pueden ser declaradas como su propia clase, o encerradas en otra clase, y entonces la sintaxis para acceder a los miembros de la enumeración depende de donde esté la enumeración declarada.

Lo siguiente NO es legal:

		public class CoffeeTest {
	
			public static void main (String[] args){
				enum CoffeeSize {BIG,HUGE,OVERWHELMING}; // MAL, no se pueden
														// declarar enumeraciones
														// en los métodos
				Coffee drink = new Coffee();
				drink.size = CoffeeSize.BIG;
			}
		}
		

Para hacer todo mas confuso, los diseñadores del lenguaje Java hizo opcional poner (;) al final de la declaración de una enumeración.

		public class CoffeeTest {
	
			enum CoffeeSize {BIG,HUGE,OVERWHELMING}; //Es opcional
			
			public static void main (String[] args){
				Coffee drink = new Coffee();
				drink.size = CoffeeSize.BIG;
				
			}
		}
		

Por tanto, ¿Qué se crea cuando ahcemos una enum? La cosa mas importante a recordar es que una enumeración no son Strings ni ints. Cada enumeración del tipo CoffeeSize son actualmente instancias de CoffeeSize. En otras palabras, BIG es un tipo de CoffeeSize. Pensemos que una enum es una especie de clase, que sería algo como lo siguiente (pero no exactamente):

		public class CoffeeSize {
			public static final CoffeeSize BIG = new CoffeeSize("BIG",0);
			public static final CoffeeSize HUGE = new CoffeeSize("HUGE",1);
			public static final CoffeeSize OVERWHELMING = new CoffeeSize("OVERWHELMING",2);
			
			public CoffeeSize (String enumName, int index){
				//Aquí la asignación
			}
			public static void main(String[] args) {
				System.out.println(CoffeeSize.BIG);
			}
		
		}
		

Vemos como cada valor de la enumeración, BIG, HUGE y OVERWHELMING son instancias del tipo CoffeeSize.

  • Declarando COnstructores, Métodos y Variables en una Enumeración

    Ya que una enum es realmente un tipo especial de clase, podemos hacer mas cosas mas que enumerar valores constantes. Podemos añadir constructores, variables de instancia, métodos y algo realmente extraño llamado “constant specific class body”. Para entender el porqué podemos necesitar mas en las enum, vamos a pensar en el siguiente escenario:

    Queremos saber el tamaño actual, en onzas, que correscponde con cada uno de las 3 constants de CofeeSize. Por ejemplo, queremos saber que BIG son 8 onzas, HUGE son 10 onzas y OVERWHELMING son 16 onzas.

    Podríamos hacer alguna especie de tabla, usando alguna estructura de datos, pero sería un disño pobre y dificil de mantener. La manera mas simple es tratar las variables de enum como objetos que cada uno puede tener sus propias variables de instancia. Entonces podemos asignar estos valores a la vez que las enumeraciones son inicializadas, pasando el valor al constructor del enum. Veamos un ejemplo en el código siguiente:

    				enum CoffeeSize {
    					// 8, 10, 16 son pasados al constructor
    					BIG(8), HUGE(10), OVERWHELMING(16);
    					CoffeeSize (int ounces){ //Constructor
    						this.ounces = ounces;
    					}
    					
    					private int ounces; //Variable de instancia
    					
    					public int getOunces(){
    						return ounces;
    					}
    				}
    				
    				class Coffee{
    					CoffeeSize size; //Cada instancia de Coffee tiene una enumeracion
    					
    					public static void main (String[] args){
    						Coffee drink1 = new Coffee();
    						drink1.size = CoffeeSize.BIG;
    						
    						Coffee drink2 = new Coffee();
    						drink2.size = CoffeeSize.HUGE;
    						
    						System.out.println (drink1.size.getOunces()); //Imprime 8
    						for (CoffeeSize cs: CoffeeSize.values())
    							System.out.println(cs + " " + cs.getOunces());
    					}
    				}
    				

    Nota: Cada enum tiene un método estático, values(), que retorna un array de valores de enumeración en orden que han sido declarados.

    Los puntos clave a recordar sobre las enum son:

    • No podemos NUNCA invocar un constructor de la enum directamente. El constructor de la enum es invocado automáticamente, con los argumentos que definimos despues del valor de la constante. BIG(8) invoca al constructor de CoffeeSize que coge el int, pasando el literal 8 al constructor.
    • Podemos definir mas de un argumento al constructor, y puedes sobrecargar al construcción del enum, como haríamos sobrecargando un constructor de una clase normal

    Finalmente, como dijimos, podemos definir algo realmente extraño en una enum que parece como una clase interna anónima. Es conocido como “constant specific class body”, y podemos usarlo cuando necesitemos que una constante en particular sustituya un método definido en la enum.

    Imaginemos este escenario:

    Queremos que la enumeracion tenga 2 métodos, uno para las onzas y otro para el código de la tapa (Como un String). Ahora queremos que la mayoría de los tamaños de los cafés usen el mismo código de tapa, “B”, pero que OVERWHELMING use el tipo “A”.

    Podemos definir un método getLidCode() en la enumeración CoffeeSize retornan “B”, pero entonces necesitaremos una manera de sustituirlo para el tamaño OVERWHELMING. No queremos hacer nada que sea dificil de mantener con if/then en el método getLidCod(), asi que el mejor enfoque puede ser la manera de hacer que OVERWHELMING pueda sustituir el método getLidCode().

    Esto parece extraño, pero necesitamos entender las reglas básicas de declaración:

    				enum CoffeeSize {
    					BIG(8),
    					HUGE(10),
    					OVERWHELMING(16){
    							//empieza un bloque de código que
    							//define el cuerpo de esta constante
    						public String getLidCode(){	//sustituye el método definido
    													// en CoffeeSize
    							return "A";
    						}
    					};
    					
    					CoffeeSize(int ounces){
    						this.ounces = ounces;
    					}
    					
    					private int ounces;
    					
    					public int getOunces(){
    						return ounces;
    					}
    					
    					public String getLidCode(){ //Este es el método sustituido
    						return "B"; //El valor por defecto que se retorna
    					}
    				}
    				

Hasta aquí este pequeño vistazo que seguramente nos ayudará un poco mejor a entender las Enumeraciones en Java, el cómo se comportan, y que podemos hacer con ellas.

Cualquier aporte o corrección o aporte es bienvenido.

Saludos!!!