Ciao! Oggi parleremo di un tipo di dati speciale in Java -
Enum
(abbreviazione di enumerazione). Qual è la loro caratteristica? Immaginiamo di dover implementare mesi nel programma. Sembrerebbe, qual è il problema? Devi solo determinare quali proprietà ha ogni mese. Forse abbiamo bisogno, prima di tutto, del nome del mese e del numero di giorni in esso contenuti. La soluzione al problema sembra abbastanza 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 +
'}';
}
}
Set completo, per favore! Abbiamo una classe Month
, i campi necessari, getter-setter, toString()
. A meno che equals()
tu hashCode()
non abbia bisogno di aggiungerlo per la completa felicità :) Tuttavia, abbiamo un problema concettuale. Come forse ricorderai, uno dei principali vantaggi dell'OOP è che semplifica la modellazione di entità del mondo reale. Una sedia, un'auto, un pianeta: tutti questi concetti della vita quotidiana sono facili da rappresentare in un programma utilizzando l'astrazione. Il problema è che alcune entità nel mondo reale hanno una gamma di significati strettamente limitata. Ci sono solo 4 stagioni in un anno. Nella musica ci sono solo 7 note. Ci sono solo 12 mesi nel calendario. Ocean ha solo 11 amici (anche se questo è discutibile :)) In altre parole, una normale classe Java non è in grado di modellare queste entità e rispettare i loro vincoli naturali. La nostra classe Month
ha tutti i campi necessari. Ma se un altro programmatore lo usa, nessuno gli impedirà di creare oggetti del tutto pazzeschi:
public class Main {
Month month1 = new Month("lolkek", 322);
Month month2 = new Month("yahoooooooooooo", 12345);
}
Se questo appare nel programma, non sarà facile trovare il colpevole! Da un lato, il programmatore che ha creato gli oggetti avrebbe potuto capire che la classe Month
significava “mese dell’anno” e non scrivere simili sciocchezze. D'altra parte, stava solo approfittando delle opportunità che gli aveva fornito il progettista della classe. Posso assegnare qualsiasi nome e numero di giorni? Lo ha nominato lui. Cosa fare in una situazione del genere? Prima del rilascio della versione 1.5 del linguaggio Java, i programmatori dovevano, francamente, uscirne :) A quei tempi, creavano i seguenti costrutti:
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 +
'}';
}
}
Qui abbiamo semplificato il numero dei mesi a tre anziché a dodici per mantenere l'esempio più breve. Tali progetti hanno permesso di risolvere il problema. Le opzioni per gli oggetti creati erano limitate da un costruttore privato:
private Month(String name, int daysCount) {
this.name = name;
this.daysCount = daysCount;
}
I programmatori che utilizzano la classe non potevano semplicemente creare file Month
. Sono stati costretti a utilizzare gli oggetti statici finali forniti dallo sviluppatore della classe. Sembrava qualcosa del genere:
public class Main {
public static void main(String[] args) {
Month january = Month.JANUARY;
System.out.println(january);
}
}
Tuttavia, gli sviluppatori Java hanno notato un problema esistente. Ovviamente è fantastico che i programmatori siano riusciti a trovare una soluzione utilizzando gli strumenti disponibili nel linguaggio, ma non sembra così semplice! Serviva una soluzione ovvia, accessibile anche ai principianti. Ecco come è apparso in Java Enum
. Essenzialmente, Enum
è una classe Java che fornisce un insieme limitato di oggetti valore. Ecco come appare:
public enum Month {
JANUARY,
FEBRUARY,
MARCH
}
Nella definizione abbiamo indicato che Enum
si tratta di una classe Java, ma è proprio vero? Sì, e possiamo anche verificarlo. Prova, ad esempio, a ereditare il nostro enum Month
da qualche altra classe:
public abstract class AbstractMonth {
}
//ошибка! No extends clause allowed to enum
public enum Month extends AbstractMonth {
JANUARY,
FEBRUARY,
MARCH
}
Perché sta succedendo? Quando scriviamo ad un programma:
public enum Month
Il compilatore converte questo comando in codice come questo:
public Class Month extends Enum
Come già sai, l'ereditarietà multipla non è consentita in Java. Pertanto, AbstractMonth
non potremmo ereditare da. Enum
Come può essere utilizzato questo nuovo design ? E in cosa differisce dal vecchio design con static final
i campi? Ebbene, ad esempio, il vecchio design non ci permetteva di utilizzare il nostro insieme di valori nelle switch
espressioni -. Immaginiamo di voler creare un programma che ci ricordi quali festività si celebrano questo mese:
public class HolidayReminder {
public void printHolidays(Month month) {
switch (month) {
//error!
case JANUARY:
}
}
}
Qui, come puoi vedere, il compilatore genera un errore. Ma dopo l'apparizione di Java 1.5 enum
, 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("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);
}
}
Uscita console:
7 января будет Рождество!
Nota: l'accesso agli oggetti Enum
rimane statico, come avveniva prima di Java 1.5. Non è necessario creare un oggetto Month
per accedere ai mesi. Quando si lavora con le enumerazioni, è molto importante non dimenticare che Enum
si tratta di una classe a tutti gli effetti. Ciò significa che, se necessario, è possibile definire costruttori e metodi al suo interno. Ad esempio, nel pezzo di codice precedente abbiamo semplicemente specificato i valori GENNAIO, FEBBRAIO, MARZO. Tuttavia, possiamo espandere il nostro enum Month
in questo modo:
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 +
'}';
}
}
Qui abbiamo aggiunto 2 campi ai nostri enum
: il nome del mese e il numero di giorni, un costruttore che utilizza questi campi, getter-setter, un metodo toString()
e 2 metodi statici. Come puoi vedere, non ci sono stati problemi con questo: come abbiamo detto prima, enum
questa è 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='Июнь', daysCount=30}, Month{name='Июль', daysCount=31}, Month{name='Август', daysCount=31}]
Infine, voglio consigliarvi un libro estremamente utile su Java, ovvero “Effective Java” di Joshua Bloch . L'autore è uno dei creatori di Java, quindi puoi sicuramente fidarti dei suoi consigli sull'uso corretto e competente degli strumenti linguistici :) In relazione alla nostra lezione, ti consiglio di prestare particolare attenzione al capitolo del libro dedicato a enum
. Buona lettura! :)
GO TO FULL VERSION