Statikus és alapértelmezett módszerek a Java interfészekben

1. Áttekintés

A Java 8 néhány vadonatúj funkciót hozott le az asztalra, beleértve a lambda kifejezéseket, a funkcionális interfészeket, a módszer referenciákat, a streameket, az Opcionális és statikus és alapértelmezett módszerek az interfészekben.

Közülük néhányat már tárgyalt ez a cikk. Ennek ellenére, statikus és alapértelmezett az interfészekben alkalmazott módszerek önmagukban érdemelnek mélyebb áttekintést.

Ebben a cikkben részletesen megvitatjuk hogyan kell használni statikus és alapértelmezett módszerek az interfészekben és át kell néznie néhány olyan felhasználási esetet, ahol hasznosak lehetnek.

2. Miért van szükség az alapértelmezett módszerekre az interfészekben?

A szokásos interfész módszerekhez hasonlóan az alapértelmezett módszerek implicit módon nyilvánosak - nem szükséges meghatározni a nyilvános módosító.

A szokásos interfész módszerektől eltérően azok kijelentette az alapértelmezett kulcsszó a metódus aláírás elején, és ők megvalósítást nyújtanak.

Lássunk egy egyszerű példát:

nyilvános felület MyInterface {// szokásos interfész módszerek default void defaultMethod () {// alapértelmezett módszer implementáció}}

Az ok, amiért alapértelmezett a Java 8 kiadásába felvett módszerek elég nyilvánvalóak.

Absztrakciókon alapuló tipikus tervezésnél, ahol egy interfésznek egy vagy több megvalósítása van, ha egy vagy több metódust adnak az interfészhez, akkor az összes megvalósítás kénytelen lesz végrehajtani azokat is. Ellenkező esetben a tervezés csak elromlik.

Az alapértelmezett interfész-módszerek hatékonyan kezelik ezt a problémát. Ők lehetővé teszi számunkra, hogy új módszereket adjunk egy interfészhez, amelyek automatikusan elérhetők a megvalósításokban. Így nincs szükség a végrehajtó osztályok módosítására.

Ily módon a visszafelé kompatibilitás szépen megmaradt anélkül, hogy át kellene alakítania a megvalósítókat.

3. Alapértelmezett interfész-módszerek működnek

A funkcionalitás jobb megértése alapértelmezett interfész módszerek, készítsünk egy egyszerű példát.

Mondd, hogy van egy naivunk Jármű felület és csak egy megvalósítás. Lehetne több is, de maradjunk ennyire egyszerűek:

nyilvános felület Jármű {String getBrand (); String speedUp (); String slowDown (); alapértelmezett String turnAlarmOn () {return "A jármű riasztójának bekapcsolása."; } alapértelmezett String turnAlarmOff () {return "A jármű riasztásának kikapcsolása."; }}

És írjuk meg a megvalósító osztályt:

public class Autóeszközök Jármű {private String márka; // konstruktorok / getters @Orride public String getBrand () {return brand; } @Orride public String speedUp () {return "Az autó gyorsul."; } @Orride public String slowDown () {return "Az autó lassul."; }} 

Végül definiáljunk egy tipikusat fő- osztály, amely létrehozza a Autó és felhívja módszereit:

public static void main (String [] args) {Jármű autó = új autó ("BMW"); System.out.println (car.getBrand ()); System.out.println (car.speedUp ()); System.out.println (car.slowDown ()); System.out.println (car.turnAlarmOn ()); System.out.println (car.turnAlarmOff ()); }

Kérjük, vegye figyelembe, hogy a alapértelmezett mód turnAlarmOn () és turnAlarmOff () tőlünk Jármű interfész van automatikusan elérhető a Autó osztály.

Továbbá, ha egy bizonyos ponton úgy döntünk, hogy adunk még egyet alapértelmezett módszerek a Jármű Az alkalmazás továbbra is működik, és nem kell arra kényszerítenünk az osztályt, hogy biztosítsa az új módszerek megvalósításait.

Az alapértelmezett módszerek tipikus használata az interfészekben hogy fokozatosan biztosítson további funkciókat egy adott típushoz anélkül, hogy lebontaná a megvalósítási osztályokat.

Ezen felül meg lehet őket szokni további funkciók biztosítása egy meglévő absztrakt módszer körül:

nyilvános felület Jármű {// további interfész-módszerek kettős getSpeed ​​(); alapértelmezett dupla getSpeedInKMH (dupla sebesség) {// conversion}}

4. Több interfész öröklési szabályai

Az alapértelmezett interfész-módszerek valóban nagyon szép funkciók, de néhány megemlítendő figyelmeztetéssel. Mivel a Java lehetővé teszi az osztályok számára, hogy több felületet valósítsanak meg, fontos tudni mi történik, ha egy osztály több, ugyanazt definiáló interfészt valósít meg alapértelmezett mód.

A forgatókönyv jobb megértése érdekében definiáljunk egy újat Riasztás interfész és refaktor a Autó osztály:

nyilvános felület Riasztás {alapértelmezett String turnAlarmOn () {return "A riasztás bekapcsolása."; } alapértelmezett String turnAlarmOff () {return "A riasztás kikapcsolása."; }}

Ezzel az új kezelőfelülettel meghatározza a saját készletét alapértelmezett módszerek, az Autó osztály mindkettőt megvalósítaná Jármű és Riasztás:

nyilvános osztály Autóeszközök Jármű, Riasztó {// ...}

Ebben az esetben, a kód egyszerűen nem fordul össze, mivel konfliktus áll fenn a több interfész öröklődése miatt (más néven a gyémántprobléma). A Autó osztály örökölné mindkét készletét alapértelmezett mód. Melyiket kellene akkor hívni?

Ennek a kétértelműségnek a megoldásához kifejezetten meg kell adnunk a módszerek megvalósítását:

@Orride public String turnAlarmOn () {// egyéni megvalósítás} @Orride public String turnAlarmOff () {// egyéni implementáció}

Azt is megtehetjük használja az osztályunk a alapértelmezett az egyik interfész módszerei.

Lássunk egy példát, amely a alapértelmezett módszerek a Jármű felület:

@Orride public String turnAlarmOn () {return Vehicle.super.turnAlarmOn (); } @Orride public String turnAlarmOff () {return Vehicle.super.turnAlarmOff (); } 

Hasonlóképpen megadhatjuk az osztálynak a alapértelmezett - a Riasztás felület:

@Orride public String turnAlarmOn () {return Alarm.super.turnAlarmOn (); } @Orride public String turnAlarmOff () {return Alarm.super.turnAlarmOff (); } 

Továbbá egyenletes lehetséges az Autó osztály használja az alapértelmezett módszerek mindkét készletét:

@Orride public String turnAlarmOn () {return Vehicle.super.turnAlarmOn () + "" + Alarm.super.turnAlarmOn (); } @Orride public String turnAlarmOff () {return Vehicle.super.turnAlarmOff () + "" + Alarm.super.turnAlarmOff (); } 

5. Statikus interfész módszerek

Eltekintve attól, hogy nyilatkozni tudjon alapértelmezett módszerek az interfészekben, A Java 8 lehetővé teszi számunkra, hogy meghatározzuk és megvalósítsuk statikus módszerek az interfészekben.

Mivel statikus A metódusok nem tartoznak egy adott objektumhoz, nem részei az interfészt megvalósító osztályok API-jának, és ennek lenniük kell a metódus nevét megelőző felületnévvel hívjuk meg.

Hogy megértsem, hogyan statikus a módszerek interfészeken működnek, alakítsuk át a Jármű felületet, és adjuk hozzá a statikus hasznossági módszer:

nyilvános felület Jármű {// rendes / alapértelmezett interfész módszerek statikus int getHorsePower (int fordulat / perc, int nyomaték) {return (ford / perc * nyomaték) / 5252; }} 

Meghatározása a statikus az interfészen belüli módszer megegyezik egy osztályban definiált módszerrel. Sőt, a statikus módszer máson belül is meghívható statikus és alapértelmezett mód.

Most mondjuk azt, hogy ki akarjuk számítani egy adott jármű motorjának lóerejét. Csak hívjuk a getHorsePower () módszer:

Vehicle.getHorsePower (2500, 480)); 

Az ötlet mögött statikus interfész módszerek egy egyszerű mechanizmus biztosítása, amely lehetővé teszi számunkra növelje a kohézió mértékét egy módszer összeállításával egyetlen helyen, anélkül, hogy objektumot kellene létrehozni.

Eléggé ugyanez megtehető absztrakt osztályokkal is. A fő különbség abban rejlik, hogy az absztrakt osztályoknak lehetnek konstruktorai, állapota és viselkedése.

Ezenkívül az interfészek statikus módszerei lehetővé teszik a kapcsolódó hasznossági módszerek csoportosítását anélkül, hogy mesterséges hasznossági osztályokat kellene létrehozni, amelyek egyszerűen helyfoglalók a statikus módszerekhez.

6. Következtetés

Ebben a cikkben alaposan feltártuk a statikus és alapértelmezett interfész módszerek a Java 8-ban. Első pillantásra ez a szolgáltatás kissé hanyagnak tűnhet, különösen objektum-orientált purista nézőpontból. Ideális esetben az interfészek nem foglalják magukba a viselkedést, és csak egy bizonyos típusú nyilvános API meghatározására használhatók.

A visszamenőleges kompatibilitás fenntartása a meglévő kóddal azonban statikus és alapértelmezett módszerek jó kompromisszumot jelentenek.

És, mint általában, a cikkben bemutatott összes kódminta elérhető a GitHubon.