Statické a predvolené metódy v rozhraniach v Jave

1. Prehľad

Java 8 priniesla k stolu niekoľko úplne nových funkcií, medzi ktoré patria výrazy lambda, funkčné rozhrania, odkazy na metódy, streamy, voliteľné a statický a predvolené metódy v rozhraniach.

Niektorým z nich sa už tento článok venoval. Avšak, statický a predvolené metódy v rozhraniach si zaslúžia hlbší pohľad na svoje vlastné.

V tomto článku sa budeme podrobne zaoberať ako použiť statický a predvolené metódy v rozhraniach a prejdime si niektoré prípady použitia, kde môžu byť užitočné.

2. Prečo sú potrebné predvolené metódy v rozhraniach

Rovnako ako bežné metódy rozhrania, predvolené metódy sú implicitne verejné - nie je potrebné špecifikovať verejné modifikátor.

Na rozdiel od bežných metód rozhrania sú deklarované s predvolené kľúčové slovo na začiatku podpisu metódy, a oni zabezpečiť implementáciu.

Pozrime sa na jednoduchý príklad:

verejné rozhranie MyInterface {// bežné metódy rozhrania default void defaultMethod () {// implementácia predvolenej metódy}}

Dôvod prečo predvolené metódy boli obsiahnuté vo vydaní Java 8, je celkom zrejmé.

V typickom dizajne založenom na abstrakciách, keď má rozhranie jednu alebo viac implementácií, ak sa k rozhraniu pridá jedna alebo viac metód, budú všetky implementácie nútené implementovať ich tiež. V opačnom prípade sa dizajn len rozpadne.

Metódy predvoleného rozhrania sú efektívnym spôsobom riešenia tejto otázky. Oni dovoľte nám pridať nové metódy do rozhrania, ktoré sú automaticky dostupné v implementáciách. Nie je teda potrebné upravovať implementačné triedy.

Touto cestou, spätná kompatibilita je úhľadne zachovaná bez nutnosti refaktorovať implementátory.

3. Predvolené metódy rozhrania v akcii

Pre lepšie pochopenie funkčnosti predvolené metódy rozhrania, vytvorme jednoduchý príklad.

Povedzme, že máme naivitu Vozidlo rozhranie a iba jedna implementácia. Môže ich byť viac, ale nechajme to také jednoduché:

verejné rozhranie Vozidlo {String getBrand (); Rýchlosť reťazca (); Reťazec slowDown (); default String turnAlarmOn () {návrat "Zapnutie alarmu vozidla."; } default String turnAlarmOff () {návrat "Vypnutie alarmu vozidla."; }}

A napíšeme implementačnú triedu:

public class Car implementuje Vehicle {private String brand; // constructors / getters @Override public String getBrand () {return brand; } @Override public String speedUp () {return "Auto sa zrýchľuje."; } @Override public String slowDown () {return "Auto spomaľuje."; }} 

Nakoniec definujeme typický hlavný trieda, ktorá vytvorí inštanciu Auto a volá jeho metódy:

public static void main (String [] args) {Vehicle car = new Car ("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 ()); }

Všimnite si, prosím, ako predvolené metódy turnAlarmOn () a turnAlarmOff () z našej Vozidlo rozhrania sú automaticky dostupné v Auto trieda.

Ďalej, ak sa v určitom okamihu rozhodneme pridať ďalšie predvolené metódy do Vozidlo rozhraní bude aplikácia naďalej fungovať a nebudeme musieť triedu nútiť, aby poskytovala implementácie nových metód.

Najbežnejšie použitie predvolených metód v rozhraniach je postupne poskytovať ďalšie funkcie danému typu bez rozbitia implementačných tried.

Okrem toho sa na ne dá zvyknúť poskytujú ďalšie funkcie okolo existujúcej abstraktnej metódy:

verejné rozhranie Vozidlo {// ďalšie metódy rozhrania double getSpeed ​​(); predvolená dvojnásobná hodnota getSpeedInKMH (dvojnásobná rýchlosť) {// prevod}}

4. Pravidlá dedenia viacerých rozhraní

Predvolené metódy rozhrania sú skutočne veľmi príjemnou funkciou, ale s niektorými výhradami, ktoré stojí za zmienku. Pretože Java umožňuje triedam implementovať viac rozhraní, je potrebné to vedieť čo sa stane, keď trieda implementuje niekoľko rozhraní, ktoré definujú to isté predvolené metódy.

Aby sme lepšie pochopili tento scenár, definujme nový Alarm rozhranie a refaktorovať Auto trieda:

verejné rozhranie Alarm {default String turnAlarmOn () {návrat "Zapnutie alarmu."; } default String turnAlarmOff () {návrat "Vypnutie budíka."; }}

S týmto novým rozhraním definuje svoju vlastnú sadu predvolené metódy, Auto trieda by implementovala oboje Vozidlo a Alarm:

verejná trieda Auto implementuje vozidlo, alarm {// ...}

V tomto prípade, kód sa jednoducho nebude kompilovať, pretože existuje konflikt spôsobený dedičnosťou viacerých rozhraní (alias diamantový problém). The Auto trieda by zdedila obe sady predvolené metódy. Ktoré z nich by sa potom mali volať?

Na vyriešenie tejto nejednoznačnosti musíme explicitne poskytnúť implementáciu metód:

@Override public String turnAlarmOn () {// vlastná implementácia} @Override public String turnAlarmOff () {// vlastná implementácia}

Môžeme tiež nechajte našu triedu používať predvolené metódy jedného z rozhraní.

Pozrime sa na príklad, ktorý používa predvolené metódy z Vozidlo rozhranie:

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

Podobne môžeme nechať triedu používať znak predvolené metódy definované v rámci Alarm rozhranie:

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

Ďalej je to dokonca možné vyrobiť Auto triedy používajú obe sady predvolených metód:

@Override public String turnAlarmOn () {návrat Vehicle.super.turnAlarmOn () + "" + Alarm.super.turnAlarmOn (); } @Override public String turnAlarmOff () {return Vehicle.super.turnAlarmOff () + "" + Alarm.super.turnAlarmOff (); } 

5. Metódy statického rozhrania

Okrem možnosti deklarovať predvolené metódy v rozhraniach, Java 8 nám umožňuje definovať a implementovať statický metódy v rozhraniach.

Odkedy statický metódy nepatria konkrétnemu objektu, nie sú súčasťou API tried implementujúcich rozhranie a musia byť volaný pomocou názvu rozhrania predchádzajúceho názvu metódy.

Aby sme pochopili ako statický metódy pracujú v rozhraniach, poďme refaktorovať Vozidlo rozhranie a pridať k nemu a statický úžitková metóda:

verejné rozhranie Vozidlo {// bežné / predvolené metódy rozhrania static int getHorsePower (int ot / min, int krútiaci moment) {návrat (ot / min * krútiaci moment) / 5252; }} 

Definovanie a statický metóda v rozhraní je identická s definíciou jednej v triede. Navyše, a statický metóda môže byť vyvolaná v rámci iných statický a predvolené metódy.

Teraz povedzme, že chceme vypočítať výkon motora daného vozidla. Len voláme getHorsePower () metóda:

Vehicle.getHorsePower (2500, 480)); 

Myšlienka v pozadí statický metód rozhrania je poskytnúť jednoduchý mechanizmus, ktorý nám to umožní zvýšiť stupeň súdržnosti spojením súvisiacich metód na jednom mieste bez nutnosti vytvorenia objektu.

Pekne veľa to isté sa dá robiť s abstraktnými triedami. Hlavný rozdiel spočíva v tom, že abstraktné triedy môžu mať konštruktory, stav a správanie.

Ďalej statické metódy v rozhraniach umožňujú zoskupovať súvisiace obslužné metódy bez toho, aby bolo potrebné vytvárať umelé triedy obslužných programov, ktoré sú jednoducho zástupnými symbolmi pre statické metódy.

6. Záver

V tomto článku sme podrobne preskúmali použitie statický a predvolené metódy rozhrania v Jave 8. Na prvý pohľad môže táto funkcia vyzerať trochu nedbalo, najmä z objektovo orientovaného puristického pohľadu. V ideálnom prípade by rozhrania nemali zapuzdrovať správanie a mali by sa používať iba na definovanie verejného rozhrania API určitého typu.

Pokiaľ však ide o zachovanie spätnej kompatibility s existujúcim kódom, statický a predvolené metódy sú dobrým kompromisom.

A ako obvykle sú všetky ukážky kódu zobrazené v tomto článku k dispozícii na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found