Enumerazioni come classi in Java
- Le enumerazioni in Java sono a tutti gli effetti un tipo di classe, permettendo l'uso di costruttori, variabili di istanza e metodi.
- Ogni costante di enumerazione è un oggetto del tipo dell'enumerazione, con il proprio stato e comportamento.
- Le enumerazioni possono essere iterate, confrontate e utilizzate in istruzioni
switch
. - I metodi
ordinal()
,compareTo()
, eequals()
sono disponibili per lavorare con le costanti di enumerazione. - Le enumerazioni, tuttavia, non possono estendere altre classi o essere estese da altre classi.
- Ogni enumerazione deriva implicitamente dalla classe
java.lang.Enum
, che fornisce metodi utili per le operazioni sulle enumerazioni.
Le Enumerazioni Java Sono Tipi di Classe
Come abbiamo già anticipato nella lezione precedente, un'enumerazione Java è un tipo di classe.
Sebbene non si istanzi una enum
usando new
, un'enumerazione ha, per il resto, molte delle stesse capacità delle altre classi.
Il fatto che enum
definisca una classe conferisce all'enumerazione Java un potere straordinario. Ad esempio, possiamo assegnare loro costruttori, aggiungere variabili di istanza e metodi, e persino implementare interfacce.
È importante capire che ogni costante di enumerazione è un oggetto del suo tipo di enumerazione. Pertanto, quando si definisce un costruttore per una enum
, il costruttore viene chiamato quando ogni costante di enumerazione viene creata. Inoltre, ogni costante di enumerazione ha la sua propria copia di qualsiasi variabile di istanza definita dall'enumerazione.
Ad esempio, si consideri la seguente versione di Mela
, già vista nella lezione precedente, che definisce un'enumerazione di varietà di mele:
// Usa un costruttore enum, variabile di istanza e metodo.
enum Mela {
// Costanti di enumerazione con prezzi.
Jonathan(10),
Golden(9),
Melannurca(12),
Winesap(15),
Cortland(8);
// Prezzo della singola mela
private int prezzo; // prezzo di ogni mela
// Costruttore
Mela(int p) {
prezzo = p;
}
int getPrezzo() {
return prezzo;
}
}
class DemoEnum3 {
public static void main(String[] args)
{
// Dichiarazione di una variabile di tipo Mela.
Mela mela;
// Visualizza il prezzo di Winesap.
System.out.println("Winesap costa " +
Mela.Winesap.getPrezzo() +
" centesimi.\n");
// Visualizza tutte le mele e i prezzi.
System.out.println("Tutti i prezzi delle mele:");
for(Mela a : Mela.values())
System.out.println(a + " costa " + a.getPrezzo() +
" centesimi.");
}
}
L'output è mostrato qui:
Winesap costa 15 centesimi.
Tutti i prezzi delle mele:
Jonathan costa 10 centesimi.
Golden costa 9 centesimi.
Melannurca costa 12 centesimi.
Winesap costa 15 centesimi.
Cortland costa 8 centesimi.
Questa versione di Mela
aggiunge tre cose:
- La prima è la variabile di istanza
prezzo
, che viene usata per contenere il prezzo di ogni varietà di mela. - La seconda è il costruttore
Mela
, al quale viene passato il prezzo di una mela. - La terza è il metodo
getPrezzo()
, che restituisce il valore diprezzo
.
Quando la variabile mela
viene dichiarata in main()
, il costruttore per Mela
viene chiamato una volta per ogni costante che è specificata. Nota come gli argomenti del costruttore sono specificati, mettendoli dentro parentesi dopo ogni costante, come mostrato qui:
Jonathan(10),
Golden(9),
Melannurca(12),
Winesap(15),
Cortland(8);
Questi valori vengono passati al parametro p
di Mela()
, che poi assegna questo valore a prezzo
. Ancora, il costruttore viene chiamato una volta per ogni costante.
Poiché ogni costante di enumerazione ha la sua propria copia di prezzo
, si può ottenere il prezzo di un tipo specificato di mela chiamando getPrezzo()
. Ad esempio, in main()
il prezzo di una Winesap è ottenuto dalla seguente chiamata:
Mela.Winesap.getPrezzo()
I prezzi di tutte le varietà sono ottenuti ciclando attraverso l'enumerazione usando un ciclo for
. Poiché c'è una copia di prezzo
per ogni costante di enumerazione, il valore associato con una costante è separato e distinto dal valore associato con un'altra costante. Questo è un concetto potente, che è disponibile solo quando le enumerazioni sono implementate come classi, come fa Java.
Sebbene l'esempio precedente contenga solo un costruttore, un enum
può offrire due o più forme di costruttori in overloading, proprio come può qualsiasi altra classe.
Ad esempio, questa versione di Mela
fornisce un costruttore predefinito che inizializza il prezzo a –1
, per indicare che non sono disponibili dati sul prezzo:
// Usa un costruttore enum.
enum Mela {
Jonathan(10),
Golden(9),
Melannurca,
Winesap(15),
Cortland(8);
// Prezzo della singola mela
private int prezzo;
// Costruttore
Mela(int p) {
prezzo = p;
}
// Costruttore sovraccaricato
Mela() {
prezzo = -1;
}
int getPrezzo() {
return prezzo;
}
}
Si noti che in questa versione, Melannurca
non riceve un argomento. Questo significa che il costruttore predefinito viene chiamato, e la variabile prezzo di Melannurca
riceve il valore –1.
Ecco due restrizioni che si applicano alle enumerazioni:
- Prima, un'enumerazione non può ereditare un'altra classe.
- Seconda, un
enum
non può essere una superclasse. Questo significa che unaenum
non può essere estesa.
In tutti gli altri casi, enum
agisce molto come qualsiasi altro tipo di classe. La chiave è ricordare che ognuna delle costanti di enumerazione è un oggetto della classe in cui è definita.
Le Enumerazioni Derivano da Enum
Anche se non è possibile derivare da una superclasse quando si dichiara una enum
, tutte le enumerazioni derivano automaticamente da una classe: java.lang.Enum
.
Questa classe definisce diversi metodi che sono disponibili per l'uso da parte di tutte le enumerazioni. Vedremo in dettaglio la classe Enum
nelle prossime lezioni, ma tre dei suoi metodi meritano una discussione in questo momento.
È possibile ottenere un valore che indica la posizione di una costante di enumerazione nella lista delle costanti. Questo è chiamato il suo valore ordinale, ed è recuperato chiamando il metodo ordinal()
, mostrato qui:
final int ordinal()
Restituisce il valore ordinale della costante che lo invoca. I valori ordinali iniziano da zero. Quindi, nell'enumerazione Mela
, Jonathan
ha un valore ordinale di zero, Golden
ha un valore ordinale di 1, Melannurca
ha un valore ordinale di 2, e così via.
È possibile confrontare il valore ordinale di due costanti della stessa enumerazione utilizzando il metodo compareTo()
. Ha questa forma generale:
final int compareTo(tipo_enum e)
Qui, tipo_enum
è il tipo dell'enumerazione, ed e
è la costante che viene confrontata con la costante che invoca il metodo. Ricordiamo che sia la costante che invoca sia e
devono essere della stessa enumerazione. Se la costante che invoca ha un valore ordinale minore di quello di e, allora compareTo()
restituisce un valore negativo. Se i due valori ordinali sono uguali, allora viene restituito zero. Se la costante che invoca ha un valore ordinale maggiore di quello di e
, allora viene restituito un valore positivo.
È possibile confrontare per uguaglianza una costante di enumerazione con qualsiasi altro oggetto utilizzando equals()
, che sovrascrive il metodo equals()
definito da Object
. Anche se equals()
può confrontare una costante di enumerazione con qualsiasi altro oggetto, quei due oggetti saranno uguali solo se entrambi si riferiscono alla stessa costante, all'interno della stessa enumerazione. Avere semplicemente valori ordinali in comune non farà sì che equals()
restituisca true se le due costanti provengono da enumerazioni diverse.
Ricordiamo che è possibile confrontare due riferimenti di enumerazione per uguaglianza utilizzando ==
. Il seguente programma dimostra i metodi ordinal()
, compareTo()
, e equals()
:
// Dimostra ordinal(), compareTo(), e equals().
// Un'enumerazione di varietà di mele.
enum Mela {
Jonathan,
Golden,
Melannurca,
Winesap,
Cortland
}
class DemoEnum4 {
public static void main(String[] args)
{
Mela me, me2, me3;
// Ottiene tutti i valori ordinali usando ordinal().
System.out.println("Ecco tutte le costanti di mela" +
" e i loro valori ordinali: ");
for(Mela m : Mela.values())
System.out.println(m + " " + m.ordinal());
me = Mela.Melannurca;
me2 = Mela.Golden;
me3 = Mela.Melannurca;
System.out.println();
// Dimostra compareTo() e equals()
if(me.compareTo(me2) < 0)
System.out.println(me + " viene prima di " + me2);
if(me.compareTo(me2) > 0)
System.out.println(me2 + " viene prima di " + me);
if(me.compareTo(me3) == 0)
System.out.println(me + " è uguale a " + me3);
System.out.println();
if(me.equals(me2))
System.out.println("Errore!");
if(me.equals(me3))
System.out.println(me + " è uguale a " + me3);
if(me == me3)
System.out.println(me + " == " + me3);
}
}
L'output del programma è mostrato qui:
Ecco tutte le costanti di mela e i loro valori ordinali:
Jonathan 0
Golden 1
Melannurca 2
Winesap 3
Cortland 4
Golden viene prima di Melannurca
Melannurca è uguale a Melannurca
Melannurca è uguale a Melannurca
Melannurca == Melannurca