JavaRush /Blog Java /Random-ES /Enumeración en Java. Ejemplos prácticos. Agregar construc...

Enumeración en Java. Ejemplos prácticos. Agregar constructores y métodos

Publicado en el grupo Random-ES
¡Hola! Hoy hablaremos sobre un tipo de datos especial en Java: Enum(abreviatura de enumeración). ¿Cuál es su característica? Imaginemos que necesitamos implementar meses en el programa. Enumeración.  Ejemplos prácticos.  Agregar constructores y métodos - 1Al parecer, ¿cuál es el problema? Sólo necesitas determinar qué propiedades tiene cada mes. Quizás necesitemos, en primer lugar, el nombre del mes y el número de días que contiene. La solución al problema parece bastante simple:
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 +
               '}';
   }
}
¡Juego completo por favor! Tenemos una clase Month, los campos necesarios, getters-setters toString(),. A menos que equals()necesites hashCode()agregarlo para una felicidad total :) Sin embargo, tenemos un problema conceptual. Como recordará, una de las principales ventajas de la programación orientada a objetos es que facilita el modelado de entidades del mundo real. Una silla, un coche, un planeta: todos estos conceptos de la vida cotidiana se pueden representar fácilmente en un programa mediante la abstracción. El problema es que algunas entidades del mundo real tienen una gama de significados estrictamente limitada. Sólo hay 4 estaciones en un año. En la música sólo hay 7 notas. Sólo hay 12 meses en el calendario. Ocean sólo tiene 11 amigos (aunque esto es discutible :)) En otras palabras, una clase Java normal no es capaz de modelar estas entidades y respetar sus restricciones naturales. Nuestra clase Monthtiene todos los campos necesarios. Pero si otro programador lo usa, nadie le impedirá crear objetos completamente locos:
public class Main {

   Month month1 = new Month("lolkek", 322);
   Month month2 = new Month("yahoooooooooooo", 12345);

}
Si esto aparece en el programa, ¡no será fácil encontrar al culpable! Por un lado, el programador que creó los objetos podría haber entendido que la clase Monthsignificaba “mes del año” y no escribir semejantes tonterías. Por otro lado, simplemente estaba aprovechando las oportunidades que le brindaba el diseñador de clases. ¿Puedo asignar cualquier nombre y número de días? Él lo nombró. ¿Qué hacer en tal situación? Antes del lanzamiento de la versión 1.5 del lenguaje Java, los programadores tenían que, francamente, salir de esto :) En aquellos días, creaban las siguientes construcciones:
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("Январь", 31);
   public static Month FEBRUARY = new Month("Февраль", 28);
   public static Month MARCH = new Month("Март", 31);

   @Override
   public String toString() {
       return "Month{" +
               "name='" + name + '\'' +
               ", daysCount=" + daysCount +
               '}';
   }
}
Aquí hemos simplificado el número de meses a tres en lugar de doce para que el ejemplo sea más breve. Tales diseños permitieron resolver el problema. Las opciones para los objetos creados estaban limitadas por 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. Se vieron obligados a utilizar los objetos estáticos finales proporcionados por el desarrollador de la clase. Se parecía a esto:
public class Main {

   public static void main(String[] args) {

       Month january = Month.JANUARY;
       System.out.println(january);
   }

}
Sin embargo, los desarrolladores de Java han notado un problema existente. Por supuesto, es fantástico que los programadores hayan podido encontrar una solución utilizando las herramientas disponibles en el lenguaje, ¡pero no parece tan simple! Se necesitaba una solución obvia, accesible incluso para los principiantes. Así apareció .en Java Enum. Básicamente, Enumes una clase Java que proporciona un conjunto limitado de objetos de valor. Así es como se ve:
public enum Month {

   JANUARY,
   FEBRUARY,
   MARCH
}
En la definición indicamos que Enumse trata de una clase Java, pero ¿es esto realmente cierto? Sí, e incluso podemos comprobarlo. Intente, por ejemplo, heredar el nuestro enum Monthde alguna otra clase:
public abstract class AbstractMonth {
}

//ошибка! No extends clause allowed to enum
public enum Month extends AbstractMonth {

   JANUARY,
   FEBRUARY,
   MARCH
}
¿Por qué está pasando esto? Cuando escribimos en un programa:
public enum Month
El compilador convierte este comando en código como este:
public Class Month extends Enum
Como ya sabes, la herencia múltiple no está permitida en Java. Por lo tanto, AbstractMonthno podríamos heredar. Enum¿Cómo se puede utilizar este nuevo diseño ? ¿Y en qué se diferencia del antiguo diseño con static finalcampos? Bueno, por ejemplo, el diseño anterior no nos permitía usar nuestro propio conjunto de valores en switch-expresiones. Imaginemos que queremos crear un programa que nos recuerde qué festivos se celebran este mes:
public class HolidayReminder {

   public void printHolidays(Month month) {

       switch (month) {

           //¡error!
           case JANUARY:
       }
   }
}
Aquí, como puede ver, el compilador arroja un error. Pero después de la aparición de Java 1.5 enum, todo se volvió mucho más sencillo:
public enum Month {

   JANUARY,
   FEBRUARY,
   MARCH
}

public class HolidayReminder {

   public void printHolidays(Month month) {

       switch (month) {

           case JANUARY:
               System.out.println("7 января будет Рождество!");
               break;
           case FEBRUARY:
               System.out.println("В феврале празднуется День Защитника Отечества - 23 февраля!");
               break;
           case MARCH:
               System.out.println("В марте отмечается Всемирный Женский День - 8 марта!");
               break;
       }
   }
}



public class Main {

   public static void main(String[] args) {

       HolidayReminder reminder = new HolidayReminder();
       reminder.printHolidays(Month.JANUARY);

   }

}
Salida de consola:

7 января будет Рождество!
Tenga en cuenta: el acceso a los objetos Enumpermanece estático, como lo era antes de Java 1.5. No necesitamos crear un objeto Monthpara acceder a meses. Cuando trabaje con enumeraciones, es muy importante no olvidar que Enumse trata de una clase completa. Esto significa que, si es necesario, puedes definir constructores y métodos en él. Por ejemplo, en el código anterior simplemente especificamos los valores ENERO, FEBRERO, MARZO. Sin embargo, podemos ampliar el nuestro enum Monthasí:
public enum Month {

   JANUARY("Январь", 31),
   FEBRUARY("Февраль", 28),
   MARCH("Март", 31),
   APRIL("Апрель", 30),
   MAY("Май", 31),
   JUNE("Июнь", 30),
   JULY("Июль", 31),
   AUGUST("Август", 31),
   SEPTEMBER("Сентябрь", 30),
   OCTOBER("Октябрь", 31),
   NOVEMBER("Ноябрь", 30),
   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í agregamos 2 campos al nuestro enum: el nombre del mes y el número de días, un constructor que usa estos campos, getters-setters, un método toString()y 2 métodos estáticos. Como puede ver, no hubo problemas con esto: como dijimos anteriormente, enumesta 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 consola:

[Month{name='Июнь', daysCount=30}, Month{name='Июль', daysCount=31}, Month{name='Август', daysCount=31}]
Finalmente, quiero recomendarles un libro extremadamente útil sobre Java, a saber, “Effective Java” de Joshua Bloch . Enumeración.  Ejemplos prácticos.  Agregar constructores y métodos - 3El autor es uno de los creadores de Java, por lo que definitivamente puedes confiar en sus consejos sobre el uso correcto y competente de las herramientas del lenguaje :) En relación con nuestra conferencia, te aconsejo que prestes especial atención al capítulo del libro dedicado a enum. ¡Que tengas una lectura productiva! :)
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION