CodeGym /Java Blog /Random-IT /Enum. Esempi pratici. Aggiunta di costruttori e metodi
John Squirrels
Livello 41
San Francisco

Enum. Esempi pratici. Aggiunta di costruttori e metodi

Pubblicato nel gruppo Random-IT
CIAO! Oggi parleremo di uno dei tipi di dati speciali di Java: Enum(abbreviazione di "enumerazione"). Cosa lo rende speciale? Immaginiamo di cosa abbiamo bisogno per implementare "mesi" in un programma. Enum.  Esempi pratici.  Aggiunta di costruttori e metodi - 1 Non sembra problematico, vero? Dobbiamo solo determinare quali proprietà ha ogni mese. Forse abbiamo prima bisogno del nome del mese e del numero di giorni in esso contenuti. La soluzione sembra piuttosto semplice:

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 +
               '}';
   }
}
L'intero shabang! Abbiamo una Monthclasse, i campi richiesti, getter/setter e toString(). A meno che, ovviamente, non sia necessario aggiungere equals()ehashCode()per raggiungere la completa felicità :) Ma qui abbiamo un problema concettuale. Come probabilmente ricorderai, uno dei principali vantaggi dell'OOP è che semplifica la modellazione di entità dal mondo reale. Una sedia, un'auto, un pianeta: tutti questi concetti della vita ordinaria possono essere facilmente rappresentati in un programma con l'aiuto dell'astrazione. Il problema è che alcune entità del mondo reale hanno un intervallo di valori strettamente limitato. Ci sono solo 4 stagioni in un anno. Ci sono solo 8 note in un'ottava. Il calendario ha solo 12 mesi. E Danny Ocean of Ocean's 11 ha solo 11 amici (anche se questo non ha importanza :)) Ciò che conta è che una normale classe Java non è in grado di modellare queste entità e far rispettare i loro limiti naturali. NostroMonthclass ha tutti i campi richiesti. Ma se un altro programmatore lo usa, nessuno può impedirgli di creare oggetti completamente folli:

public class Main {

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

}
Se questo appare nel nostro codice, non sarà facile trovare il colpevole! Da un lato, il programmatore che crea gli oggetti potrebbe rendersi conto che la Monthclasse significa "mese in un anno" e non scrivere simili sciocchezze. D'altra parte, il programmatore sfrutta solo le abilità fornite dal progettista della classe. È possibile assegnare nomi e numeri di giorni arbitrari? Questo è esattamente ciò che abbiamo ottenuto. Cosa dovremmo fare allora in questa situazione? Onestamente, prima del rilascio di Java 1.5, i programmatori dovevano diventare creativi :) A quei tempi, creavano strutture come questa:

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 +
               '}';
   }
}
Qui abbiamo ridotto il numero di mesi da dodici a tre per accorciare l'esempio. Tali progetti hanno permesso di risolvere il problema. La capacità di creare oggetti era limitata a un costruttore privato:

private Month(String name, int daysCount) {
       this.name = name;
       this.daysCount = daysCount;
   }
I programmatori che utilizzano la classe non possono semplicemente creare Monthoggetti. Hanno dovuto utilizzare gli oggetti statici finali forniti dallo sviluppatore della classe. Ad esempio, in questo modo:

public class Main {

   public static void main(String[] args) {

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

}
Ma gli sviluppatori Java hanno attirato l'attenzione sul problema esistente. Certo, è fantastico che i programmatori siano riusciti a trovare una soluzione utilizzando gli strumenti disponibili nella lingua, ma non sembra molto facile! Era necessaria una soluzione ovvia, anche per i novizi. E così Enumè apparso in Java. Fondamentalmente, Enumè una classe Java che fornisce un insieme limitato di valori oggetto. Ecco come appare:

public enum Month {
  
   JANUARY,
   FEBRUARY,
   MARCH
}
Nella definizione abbiamo indicato che Enumsi tratta di una classe Java, ma è proprio vero? Sì, e possiamo anche verificarlo. Ad esempio, prova a fare in modo che il nostro Monthenum erediti un'altra classe:

public abstract class AbstractMonth {
}

// Error! The extends clause cannot be used with an enum
public enum Month extends AbstractMonth {

   JANUARY,
   FEBRUARY,
   MARCH
}
Perché succede? Quando scriviamo:

public enum Month
il compilatore converte questa istruzione nel seguente codice:

public Class Month extends Enum
Come già sai, Java non supporta l'ereditarietà multipla. Pertanto, non possiamo ereditare AbstractMonth. EnumCome può essere utilizzato questo nuovo costrutto, ? E in cosa differisce dal vecchio costrutto con static finali campi? Ebbene, ad esempio, il vecchio costrutto non ci permetteva di utilizzare il nostro insieme di valori nelle switchistruzioni. Immagina di voler creare un programma che ci ricorderà le festività celebrate ogni mese:

public class HolidayReminder {

   public void printHolidays(Month month) {

       switch (month) {

           // Error!
           case JANUARY:
       }
   }
}
Come puoi vedere, il compilatore genera un errore qui. Ma una volta enumapparso in Java 1.5, tutto è diventato molto più semplice:

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);

   }

}
Uscita console:

New Year's Day is January 1st!
Si noti che l'accesso agli Enumoggetti è rimasto statico, proprio come lo era prima di Java 1.5. Non abbiamo bisogno di creare un Monthoggetto per accedere ai mesi. Quando si lavora con gli enum, è molto importante non dimenticare che Enumsi tratta di una classe a tutti gli effetti. Ciò significa che, se necessario, è possibile definire costruttori e metodi al suo interno. Ad esempio, nel frammento di codice precedente, abbiamo semplicemente specificato i valori: GENNAIO, FEBBRAIO, MARZO. Tuttavia, possiamo espandere il nostro Monthenum in questo modo:

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 +
               '}';
   }
}
Qui abbiamo fornito i nostri enum2 campi (il nome del mese e il numero di giorni), un costruttore che utilizza questi campi, getter/setter, il toString()metodo e 2 metodi statici. Come puoi vedere, non ci sono stati problemi con questo. Ancora una volta, Enumè davvero una classe a tutti gli effetti:

import java.util.Arrays;

public class Main {

   public static void main(String[] args) {

       System.out.println(Arrays.toString(Month.getSummerMonths()));

   }

}
Uscita console:

[Month{name='June', daysCount=30}, Month{name='July', daysCount=31}, Month{name='August', daysCount=31}]
Infine, voglio consigliare un libro Java estremamente utile, vale a dire "Effective Java" di Joshua Bloch . Enum.  Esempi pratici.  Aggiunta di costruttori e metodi - 3L'autore è uno dei creatori di Java, quindi puoi sicuramente fidarti dei suoi consigli su come utilizzare correttamente e con competenza gli strumenti del linguaggio :) Per quanto riguarda la nostra lezione, ti consiglio di prestare particolare attenzione al capitolo del libro su Enum. Buona lettura! :)
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION