Java Academy · Oppitunti

Abstraktit metodit enumeissa

Vakiokohtainen toiminta.

Oppitunti 2/413 vaihetta

Abstraktit metodit enumeissa on ilmainen Java Academy-oppitunti CoddyKitissä. Tämä on oppitunti 2/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Java Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Java Academy-kurssilla on yhteensä 4 oppituntia.

Vakiokohtainen toiminta

Joskus jokainen enum-vakio tarvitsee erilaista toimintaa, ei vain erilaisia tietoja.

Javassa enum-tyypille voi määrittää abstraktin metodin ja ylikirjoittaa sen jokaisen vakion kohdalla. Tätä kutsutaan vakiokohtaisen metodirungon malliksi.

public class Main {
    enum Operation {
        PLUS { public int apply(int a, int b) { return a + b; } },
        MINUS { public int apply(int a, int b) { return a - b; } };
        public abstract int apply(int a, int b);
    }
    public static void main(String[] args) {
        System.out.println(Operation.PLUS.apply(3, 4));
        System.out.println(Operation.MINUS.apply(10, 6));
    }
}

Näin se toimii

Jokaisesta vakioista, jolla on oma runkonsa, tulee enum-tyypin nimetön aliluokka.

Abstrakti metodi pakottaa jokaisen vakion tarjoamaan toteutuksen, joten kääntäjä varmistaa kattavuuden.

public class Main {
    enum Operation {
        TIMES { public int apply(int a, int b) { return a * b; } };
        public abstract int apply(int a, int b);
    }
    public static void main(String[] args) {
        // The constant is an instance of a generated subclass
        System.out.println(Operation.TIMES.getClass().getSimpleName().isEmpty()
            ? "anonymous subclass" : Operation.TIMES.apply(6, 7));
    }
}

Täysi laskin

Neljä aritmeettista operaatiota vakioina, joista jokaisella on oma apply-metodin toteutuksensa.

public class Main {
    enum Operation {
        PLUS  { public double apply(double a, double b) { return a + b; } },
        MINUS { public double apply(double a, double b) { return a - b; } },
        TIMES { public double apply(double a, double b) { return a * b; } },
        DIVIDE{ public double apply(double a, double b) { return a / b; } };
        public abstract double apply(double a, double b);
    }
    public static void main(String[] args) {
        double x = 6, y = 3;
        for (Operation op : Operation.values()) {
            System.out.printf("%s -> %.1f%n", op, op.apply(x, y));
        }
    }
}

Kenttien ja toiminnan yhdistäminen

Voitte yhdistää kentän, kuten symbolin, vakiokohtaiseen toimintaan. Kenttä nimeää operaation ja metodi suorittaa sen.

public class Main {
    enum Operation {
        PLUS("+")  { public double apply(double a, double b) { return a + b; } },
        MINUS("-") { public double apply(double a, double b) { return a - b; } };
        private final String symbol;
        Operation(String symbol) { this.symbol = symbol; }
        public abstract double apply(double a, double b);
        @Override public String toString() { return symbol; }
    }
    public static void main(String[] args) {
        Operation op = Operation.PLUS;
        System.out.println("2 " + op + " 3 = " + op.apply(2, 3));
    }
}

Miksei switch-lauseketta?

Voisitte toteuttaa apply-metodin yhdellä vakioon kohdistuvalla switch-lausekkeella, mutta abstraktiin metodiin perustuva ratkaisu on turvallisempi.

Jos lisäätte myöhemmin uuden vakion, kääntäjä pakottaa teidät antamaan sille oman toteutuksensa. Switch-lauseke voisi ohittaa uuden tapauksen huomaamatta.

public class Main {
    enum Op {
        SQUARE { public int apply(int n) { return n * n; } },
        CUBE   { public int apply(int n) { return n * n * n; } };
        public abstract int apply(int n);
    }
    public static void main(String[] args) {
        System.out.println(Op.SQUARE.apply(5));
        System.out.println(Op.CUBE.apply(3));
    }
}

Konkreettiset metodit abstraktien rinnalla

Enum-tyypissä voi yhdistää abstrakteja ja konkreettisia metodeja. Yhteinen logiikka sijoitetaan konkreettiseen metodiin ja vaihteleva logiikka jätetään abstraktiksi.

public class Main {
    enum Shape {
        CIRCLE { public double area(double x) { return Math.PI * x * x; } },
        SQUARE { public double area(double x) { return x * x; } };
        public abstract double area(double x);
        public String report(double x) { return this + " area = " + area(x); }
    }
    public static void main(String[] args) {
        System.out.println(Shape.CIRCLE.report(2));
    }
}

Strategia-enumit

Yksi kehitysaskel on strategia-enum: vakiot delegoivat sisäkkäiselle strategia-enumille sen sijaan, että ylikirjoittaisivat metodin suoraan.

Tämä on hyödyllistä, kun useat vakiot jakavat saman toiminnan. Tässä esimerkissä arkipäivien ja viikonloppujen palkkalaskenta eroaa toisistaan.

public class Main {
    enum PayType {
        WEEKDAY { int overtime(int mins) { return mins; } },
        WEEKEND { int overtime(int mins) { return mins * 2; } };
        abstract int overtime(int mins);
        int pay(int mins) { return mins + overtime(Math.max(0, mins - 480)); }
    }
    public static void main(String[] args) {
        System.out.println("Weekend pay: " + PayType.WEEKEND.pay(540));
    }
}

Enum-tyyppi rajapinnalla ja vakiokohtaisilla toteutuksilla

Yhdistämällä rajapinnan ja vakiokohtaiset toteutukset saatte mahdollisimman monipuolisen polymorfismin.

public class Main {
    interface Command { String run(); }
    enum Action implements Command {
        START { public String run() { return "starting..."; } },
        STOP  { public String run() { return "stopping..."; } };
    }
    public static void main(String[] args) {
        for (Action a : Action.values()) System.out.println(a.run());
    }
}

Kenttien käyttö toteutuksista

Vakiokohtainen toteutus voi lukea oman vakionsa kenttiä, koska kukin toteutus suoritetaan kyseisen instanssin kontekstissa.

public class Main {
    enum Tax {
        STANDARD(0.20) { double apply(double amt) { return amt * (1 + rate); } },
        REDUCED(0.05)  { double apply(double amt) { return amt * (1 + rate); } };
        protected final double rate;
        Tax(double rate) { this.rate = rate; }
        abstract double apply(double amt);
    }
    public static void main(String[] args) {
        System.out.printf("%.2f%n", Tax.STANDARD.apply(100));
    }
}

Oletustoteutus ja ylikirjoitus

Voitte antaa enum-tyypin rungossa konkreettisen oletustoteutuksen ja ylikirjoittaa sen vain niiden vakioiden kohdalla, jotka poikkeavat oletuksesta.

public class Main {
    enum Notifier {
        EMAIL,
        SMS { String send(String m) { return "SMS: " + m; } };
        String send(String m) { return "EMAIL: " + m; }
    }
    public static void main(String[] args) {
        System.out.println(Notifier.EMAIL.send("hi"));
        System.out.println(Notifier.SMS.send("hi"));
    }
}

Pieni tilakone

Vakiokohtainen toiminta on parhaimmillaan tilakoneissa: jokainen tila tuntee oman siirtymänsä.

public class Main {
    enum State {
        IDLE    { State next() { return RUNNING; } },
        RUNNING { State next() { return DONE; } },
        DONE    { State next() { return DONE; } };
        abstract State next();
    }
    public static void main(String[] args) {
        State s = State.IDLE;
        for (int i = 0; i < 3; i++) { System.out.println(s); s = s.next(); }
        System.out.println(s);
    }
}

Pikatesti

Testatkaa ymmärrystänne enum-tyyppien abstrakteista metodeista.

Kertaus

Opitte vakiokohtaisesta toiminnasta:

  • Määritä abstrakti metodi ja ylikirjoita se jokaisen vakion rungossa.
  • Jokaisesta vakiosta tulee nimetön aliluokka.
  • Kääntäjä valvoo kattavuutta, joten ratkaisu on switch-lauseketta varmempi.
  • Monipuolisissa enum-tyypeissä voi yhdistää kenttiä, konkreettisia oletustoteutuksia ja rajapintoja.

Seuraavaksi käsitellään suorituskykyistä EnumSet-tyyppiä.

public class Main {
    enum E { A { int v() { return 1; } }; abstract int v(); }
    public static void main(String[] args) {
        System.out.println("Abstract enum recap: " + E.A.v());
    }
}
Aloita maksutta

Opi Java tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
104
Oppitunnit
374

Usein kysytyt kysymykset

Onko oppitunti ”Abstraktit metodit enumeissa” ilmainen?

Kyllä – oppitunnin ”Abstraktit metodit enumeissa” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Java Academy-kurssin, päivitä CoddyKit PROhon. Java Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Abstraktit metodit enumeissa”?

Vakiokohtainen toiminta. Harjoittelet Java Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Java Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Java Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/4.

Kuinka kauan ”Abstraktit metodit enumeissa”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Java Academy-oppitunnilla?

Kyllä. Jokainen Java Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Enumit kenttien ja metodien kanssa
  2. Abstraktit metodit enumeissa
  3. EnumSet
  4. EnumMap
← Takaisin: Java Academy