CodeGym /Java-blogg /Tilfeldig /Enum. Praktiske eksempler. Legge til konstruktører og met...
John Squirrels
Nivå
San Francisco

Enum. Praktiske eksempler. Legge til konstruktører og metoder

Publisert i gruppen
Hei! I dag skal vi snakke om en av Javas spesielle datatyper: Enum(forkortelse for "enumeration"). Hva gjør det spesielt? La oss forestille oss hva vi trenger for å implementere "måneder" i et program. Enum.  Praktiske eksempler.  Legge til konstruktører og metoder - 1 Virker ikke problematisk, ikke sant? Vi trenger bare å finne ut hvilke egenskaper den ene måneden har. Kanskje trenger vi først navnet på måneden og antall dager i den. Løsningen ser ganske enkel ut:

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 +
               '}';
   }
}
Hele sjabben! Vi har en Monthklasse, de obligatoriske feltene, getter/settere og toString(). Med mindre vi selvfølgelig må legge til equals()oghashCode()å oppnå fullstendig lykke :) Men her har vi et konseptuelt problem. Som du sikkert husker, er en av hovedfordelene med OOP at det gjør det enkelt å modellere enheter fra den virkelige verden. En stol, en bil, en planet — alle disse konseptene fra det vanlige livet er lett representert i et program ved hjelp av abstraksjon. Problemet er at enkelte enheter i den virkelige verden har et strengt begrenset verdiområde. Det er bare 4 sesonger i løpet av et år. Det er bare 8 toner i en oktav. Kalenderen har kun 12 måneder. Og Danny Ocean of Ocean's 11 har bare 11 venner (selv om dette ikke spiller noen rolle :)) Det som betyr noe er at en vanlig Java-klasse ikke er i stand til å modellere disse enhetene og håndheve deres naturlige begrensninger. VårMonthklasse har alle de obligatoriske feltene. Men hvis en annen programmerer bruker det, kan ingen stoppe ham eller henne fra å lage helt sinnsyke objekter:

public class Main {

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

}
Hvis dette vises i koden vår, vil det ikke være lett å finne den skyldige! På den ene siden kan programmereren som lager objektene innse at klassen Monthbetyr "måned i et år" og ikke skrive slikt tull. På den annen side utnytter programmereren bare evner som klassedesigneren ga. Er det mulig å tildele vilkårlige navn og antall dager? Det er akkurat det vi fikk. Hva bør vi da gjøre i denne situasjonen? Ærlig talt, før Java 1.5 ble utgitt, måtte programmerere være kreative :) På den tiden laget de strukturer som dette:

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 +
               '}';
   }
}
Her har vi kuttet antall måneder fra tolv til tre for å gjøre eksemplet kortere. Slike design gjorde det mulig å løse problemet. Muligheten til å lage objekter var begrenset til en privat konstruktør:

private Month(String name, int daysCount) {
       this.name = name;
       this.daysCount = daysCount;
   }
Programmerere som bruker klassen kunne ikke bare lage Monthobjekter. De måtte bruke de endelige statiske objektene levert av klasseutvikleren. For eksempel slik:

public class Main {

   public static void main(String[] args) {

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

}
Men Java-utviklere trakk oppmerksomheten til det eksisterende problemet. Selvfølgelig er det flott at programmerere klarte å komme opp med en løsning ved å bruke verktøyene som er tilgjengelige på språket, men det ser ikke veldig enkelt ut! En åpenbar løsning var nødvendig, selv for nybegynnere. Og så Enumdukket det opp i Java. I utgangspunktet Enumer det en Java-klasse som gir et begrenset sett med objektverdier. Slik ser det ut:

public enum Month {
  
   JANUARY,
   FEBRUARY,
   MARCH
}
I definisjonen indikerte vi at det Enumer en Java-klasse, men er det virkelig sant? Ja, og vi kan til og med bekrefte det. For eksempel, prøv å få Monthenumen vår til å arve en annen klasse:

public abstract class AbstractMonth {
}

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

   JANUARY,
   FEBRUARY,
   MARCH
}
Hvorfor skjer det? Når vi skriver:

public enum Month
kompilatoren konverterer denne setningen til følgende kode:

public Class Month extends Enum
Som du allerede vet, støtter ikke Java multippel arv. Derfor kan vi ikke arve AbstractMonth. Hvordan kan denne nye konstruksjonen Enumbrukes? Og hvordan skiller den seg fra den gamle konstruksjonen med static finalfelt? Vel, som et eksempel, den gamle konstruksjonen lot oss ikke bruke vårt eget sett med verdier i switchutsagn. Tenk deg at vi ønsker å lage et program som minner oss om høytidene som feires hver måned:

public class HolidayReminder {

   public void printHolidays(Month month) {

       switch (month) {

           // Error!
           case JANUARY:
       }
   }
}
Som du kan se, kaster kompilatoren en feil her. Men når du først enumdukket opp i Java 1.5, ble alt mye enklere:

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

   }

}
Konsoll utgang:

New Year's Day is January 1st!
Merk at tilgangen til Enumobjekter forble statisk, akkurat som før Java 1.5. Vi trenger ikke opprette et Monthobjekt for å få tilgang til månedene. Når du jobber med enums, er det veldig viktig å ikke glemme at det Enumer en fullverdig klasse. Dette betyr at du om nødvendig kan definere konstruktører og metoder i den. For eksempel, i forrige kodefragment spesifiserte vi ganske enkelt verdiene: JANUAR, FEBRUAR, MARS. Vi kan imidlertid utvide Monthopptellingen vår slik:

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 +
               '}';
   }
}
Her ga vi våre enum2 felter (navnet på måneden og antall dager), en konstruktør som bruker disse feltene, getter/settere, metoden toString()og 2 statiske metoder. Som du ser var det ingen problemer med dette. Igjen, Enumer virkelig en fullverdig klasse:

import java.util.Arrays;

public class Main {

   public static void main(String[] args) {

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

   }

}
Konsoll utgang:

[Month{name='June', daysCount=30}, Month{name='July', daysCount=31}, Month{name='August', daysCount=31}]
Til slutt vil jeg anbefale en ekstremt nyttig Java-bok, nemlig «Effektiv Java» av Joshua Bloch . Enum.  Praktiske eksempler.  Legge til konstruktører og metoder - 3Forfatteren er en av Javas skapere, så du kan definitivt stole på hans råd om hvordan du bruker språkets verktøy riktig og kompetent :) Når det gjelder leksjonen vår, anbefaler jeg at du legger spesielt merke til bokens kapittel om Enum. God lesning! :)
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION