¡Hola! Hoy hablaremos sobre uno de los tipos de datos especiales de Java:
No parece problemático, ¿verdad? Solo necesitamos determinar qué propiedades tiene cualquier mes. Quizás primero necesitemos el nombre del mes y la cantidad de días que contiene. La solución parece bastante simple:
El autor es uno de los creadores de Java, por lo que definitivamente puede confiar en sus consejos sobre cómo usar correctamente y de manera competente las herramientas del lenguaje :) Con respecto a nuestra lección, le recomiendo que preste especial atención al capítulo del libro sobre
Enum
(abreviatura de "enumeración"). ¿Qué lo hace especial? Imaginemos lo que necesitamos para implementar "meses" en un programa. 
public class Month {
private String name;
private int daysCount;
public Month(String name, int daysCount) {
this.name = name;
this.daysCount = daysCount;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getDaysCount() {
return daysCount;
}
public void setDaysCount(int daysCount) {
this.daysCount = daysCount;
}
@Override
public String toString() {
return "Month{" +
"name='" + name + '\'' +
", daysCount=" + daysCount +
'}';
}
}
¡Todo el shabang! Tenemos una Month
clase, los campos requeridos, getter/setters y toString()
. A menos, por supuesto, que necesitemos agregar equals()
yhashCode()
para alcanzar la felicidad completa :) Pero aquí tenemos un problema conceptual. Como probablemente recuerde, una de las principales ventajas de OOP es que facilita el modelado de entidades del mundo real. Una silla, un automóvil, un planeta: todos estos conceptos de la vida cotidiana se representan fácilmente en un programa con la ayuda de la abstracción. El problema es que algunas entidades del mundo real tienen un rango de valores estrictamente limitado. Solo hay 4 estaciones en un año. Hay solo 8 notas en una octava. El calendario tiene apenas 12 meses. Y Danny Ocean of Ocean's 11 tiene solo 11 amigos (aunque esto no importa :)) Lo que importa es que una clase ordinaria de Java no puede modelar estas entidades y hacer cumplir sus limitaciones naturales. NuestroMonth
La clase tiene todos los campos obligatorios. Pero si otro programador lo usa, nadie puede impedirle crear objetos completamente locos:
public class Main {
Month month1 = new Month("lolkek", 322);
Month month2 = new Month("yahoooooooooooo", 12345);
}
Si esto aparece en nuestro código, ¡no será fácil encontrar al culpable! Por un lado, el programador que crea los objetos podría darse cuenta de que la Month
clase significa "mes en un año" y no escribir esas tonterías. Por otro lado, el programador solo está aprovechando las habilidades que proporcionó el diseñador de la clase. ¿Es posible asignar nombres y números de días arbitrarios? Eso es exactamente lo que tenemos. ¿Qué debemos hacer entonces en esta situación? Honestamente, antes de que se lanzara Java 1.5, los programadores tenían que ser creativos :) En aquellos días, creaban estructuras como esta:
public class Month {
private String name;
private int daysCount;
private Month(String name, int daysCount) {
this.name = name;
this.daysCount = daysCount;
}
public static Month JANUARY = new Month("January", 31);
public static Month FEBRUARY = new Month("February", 28);
public static Month MARCH = new Month("March", 31);
@Override
public String toString() {
return "Month{" +
"name='" + name + '\'' +
", daysCount=" + daysCount +
'}';
}
}
Aquí hemos reducido el número de meses de doce a tres para acortar el ejemplo. Tales diseños permitieron resolver el problema. La capacidad de crear objetos estaba limitada a un constructor privado:
private Month(String name, int daysCount) {
this.name = name;
this.daysCount = daysCount;
}
Los programadores que usaban la clase no podían simplemente crear Month
objetos. Tuvieron que usar los objetos estáticos finales proporcionados por el desarrollador de la clase. Por ejemplo, así:
public class Main {
public static void main(String[] args) {
Month january = Month.JANUARY;
System.out.println(january);
}
}
Pero, los desarrolladores de Java llamaron la atención sobre el problema existente. Por supuesto, es genial que los programadores hayan podido encontrar una solución utilizando las herramientas disponibles en el lenguaje, ¡pero no parece muy fácil! Se necesitaba una solución obvia, incluso para los novatos. Y así Enum
apareció en Java. Básicamente, Enum
es una clase de Java que proporciona un conjunto limitado de valores de objetos. Así es como se ve:
public enum Month {
JANUARY,
FEBRUARY,
MARCH
}
En la definición, indicamos que Enum
es una clase de Java, pero ¿es eso realmente cierto? Sí, e incluso podemos verificarlo. Por ejemplo, intente hacer que nuestra Month
enumeración herede alguna otra clase:
public abstract class AbstractMonth {
}
// Error! The extends clause cannot be used with an enum
public enum Month extends AbstractMonth {
JANUARY,
FEBRUARY,
MARCH
}
¿Por qué sucede eso? Cuando escribimos:
public enum Month
el compilador convierte esta declaración en el siguiente código:
public Class Month extends Enum
Como ya sabes, Java no admite la herencia múltiple. Por lo tanto, no podemos heredar AbstractMonth
. Enum
¿Cómo se puede usar esta nueva construcción ? ¿Y en qué se diferencia de la construcción anterior con static final
campos? Bueno, como ejemplo, la construcción anterior no nos permitía usar nuestro propio conjunto de valores en switch
las declaraciones. Imagina que queremos crear un programa que nos recuerde las fiestas que se celebran cada mes:
public class HolidayReminder {
public void printHolidays(Month month) {
switch (month) {
// Error!
case JANUARY:
}
}
}
Como puede ver, el compilador arroja un error aquí. Pero una vez que enum
apareció en Java 1.5, todo se volvió mucho más simple:
public enum Month {
JANUARY,
FEBRUARY,
MARCH
}
public class HolidayReminder {
public void printHolidays(Month month) {
switch (month) {
case JANUARY:
System.out.println("New Year's Day is January 1st!");
break;
case FEBRUARY:
System.out.println("Valentine's Day is February 14th!");
break;
case MARCH:
System.out.println("Saint Patrick's Day is March 17th!");
break;
}
}
}
public class Main {
public static void main(String[] args) {
HolidayReminder reminder = new HolidayReminder();
reminder.printHolidays(Month.JANUARY);
}
}
Salida de la consola:
New Year's Day is January 1st!
Tenga en cuenta que el acceso a Enum
los objetos permaneció estático, tal como era antes de Java 1.5. No necesitamos crear un Month
objeto para acceder a los meses. Cuando se trabaja con enumeraciones, es muy importante no olvidar que Enum
es una clase completa. Esto significa que, si es necesario, puede definir constructores y métodos en él. Por ejemplo, en el fragmento de código anterior, simplemente especificamos los valores: ENERO, FEBRERO, MARZO. Sin embargo, podemos expandir nuestra Month
enumeración de esta manera:
public enum Month {
JANUARY("January", 31),
FEBRUARY("February", 28),
MARCH("March", 31),
APRIL("April", 30),
MAY("May", 31),
JUNE("June", 30),
JULY("July", 31),
AUGUST("August", 31),
SEPTEMBER("September", 30),
OCTOBER("October", 31),
NOVEMBER("November", 30),
DECEMBER("December", 31);
private String name;
private int daysCount;
Month(String name, int daysCount) {
this.name = name;
this.daysCount = daysCount;
}
public static Month[] getWinterMonths() {
return new Month[]{DECEMBER, JANUARY, FEBRUARY};
}
public static Month[] getSummerMonths() {
return new Month[]{JUNE, JULY, AUGUST};
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getDaysCount() {
return daysCount;
}
public void setDaysCount(int daysCount) {
this.daysCount = daysCount;
}
@Override
public String toString() {
return "Month{" +
"name='" + name + '\'' +
", daysCount=" + daysCount +
'}';
}
}
Aquí le dimos a nuestros enum
2 campos (el nombre del mes y el número de días), un constructor que usa estos campos, getter/setters, el toString()
método y 2 métodos estáticos. Como puede ver, no hubo problemas con esto. Nuevamente, Enum
realmente es una clase completa:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
System.out.println(Arrays.toString(Month.getSummerMonths()));
}
}
Salida de la consola:
[Month{name='June', daysCount=30}, Month{name='July', daysCount=31}, Month{name='August', daysCount=31}]
Finalmente, quiero recomendar un libro de Java extremadamente útil, a saber, "Effective Java" de Joshua Bloch . 
Enum
. ¡Feliz lectura! :)
GO TO FULL VERSION