Uzavreté triedy a rozhrania v Jave 15

1. Prehľad

Uvoľnenie Java SE 15 zavádza zapečatené triedy (JEP 360) ako funkciu ukážky.

Táto funkcia sa týka umožnenia podrobnejšej kontroly dedičstva v Jave. Utesnenie umožňuje triedam a rozhraniam definovať ich povolené podtypy.

Inými slovami, trieda alebo rozhranie môžu teraz definovať, ktoré triedy ich môžu implementovať alebo rozšíriť. Je to užitočná funkcia na modelovanie domén a na zvýšenie bezpečnosti knižníc.

2. Motivácia

Hierarchia tried nám umožňuje opätovne použiť kód prostredníctvom dedičstva. Hierarchia tried však môže mať aj iné účely. Opätovné použitie kódu je skvelé, ale nie vždy je našim primárnym cieľom.

2.1. Možnosti modelovania

Alternatívnym účelom hierarchie tried môže byť modelovanie rôznych možností, ktoré existujú v doméne.

Ako príklad si predstavte obchodnú doménu, ktorá funguje iba s osobnými a nákladnými vozidlami, nie s motocyklami. Pri vytváraní Vozidlo abstraktnej triedy v Jave, mali by sme byť schopní povoliť iba Auto a Nákladné auto triedy ju predĺžiť. Týmto spôsobom chceme zabezpečiť, aby nedochádzalo k zneužitiu Vozidlo abstraktná trieda v našej doméne.

V tomto príklade nás viac ako obrana proti všetkým neznámym podtriedam zaujíma jasnosť spracovania kódu so známymi podtriedami.

Pred verziou 15 Java predpokladala, že opätovné použitie kódu je vždy cieľom. Každú triedu bolo možné rozšíriť o ľubovoľný počet podtried.

2.2. Balík-súkromný prístup

V starších verziách poskytovala Java obmedzené možnosti v oblasti riadenia dedičstva.

Finálna trieda nemôže mať žiadne podtriedy. Trieda súkromného balíka môže mať v rovnakom balíku iba podtriedy.

Pomocou prístupu balíka a súkromia nemôžu používatelia pristupovať k abstraktnej triede bez toho, aby im umožnili rozšíriť ju:

public class Vehicles {abstract static class Vehicle {private final String registrationNumber; verejné vozidlo (String registrationNumber) {this.registrationNumber = registrationNumber; } public String getRegistrationNumber () {vrátiť registračné číslo; }} public static final class Car extends Vehicle {private final int numberOfSeats; public Car (int numberOfSeats, String registrationNumber) {super (registrationNumber); this.numberOfSeats = numberOfSeats; } public int getNumberOfSeats () {return numberOfSeats; }} public static final class Truck truck extends Vehicle {private final int loadCapacity; public Truck (int loadCapacity, String registrationNumber) {super (registrationNumber); this.loadCapacity = loadCapacity; } public int getLoadCapacity () {return loadCapacity; }}}

2.3. Nadtrieda prístupná, nerozšíriteľná

Nadtrieda, ktorá je vyvinutá so sadou jej podtried, by mala byť schopná dokumentovať zamýšľané použitie, nie obmedzovať svoje podtriedy. Obmedzené podtriedy by tiež nemali obmedzovať prístupnosť svojej nadtriedy.

Hlavnou motiváciou zapečatených tried je teda mať možnosť, aby bola nadtrieda široko prístupná, ale nie veľmi rozšíriteľná.

3. Tvorba

Zapečatená funkcia zavádza v Jave niekoľko nových modifikátorov a klauzúl: zapečatené, nezapečatené, a povolenia.

3.1. Zapečatené rozhrania

Na utesnenie rozhrania môžeme použiť zapečatené modifikátor jeho vyhlásenia. The povolenia klauzula potom určuje triedy, ktoré sú povolené na implementáciu zapečateného rozhrania:

verejné zapečatené rozhranie Služba umožňuje Car, Truck {int getMaxServiceIntervalInMonths (); default int getMaxDistanceB BetweenServicesInKilometers () {návrat 100000; }}

3.2. Uzavreté triedy

Podobne ako rozhrania, aj triedy môžeme zapečatiť ich použitím zapečatené modifikátor. The povolenia doložka by mala byť definovaná za ľubovoľnou predlžuje alebo náradie doložky:

verejná abstraktná zapečatená trieda Vozidlo povoľuje auto, nákladné auto {chránené konečné číslo registrácie reťazca; verejné vozidlo (String registrationNumber) {this.registrationNumber = registrationNumber; } public String getRegistrationNumber () {vrátiť registračné číslo; }}

Povolená podtrieda musí definovať modifikátor. Môže to byť vyhlásené konečné ako zabrániť ďalším rozšíreniam:

verejná konečná trieda Nákladné vozidlo rozširuje Vozidlo implementuje službu {private final int loadCapacity; public Truck (int loadCapacity, String registrationNumber) {super (registrationNumber); this.loadCapacity = loadCapacity; } public int getLoadCapacity () {return loadCapacity; } @Override public int getMaxServiceIntervalInMonths () {návrat 18; }}

Môže sa tiež deklarovať povolená podtrieda zapečatené. Ak to však deklarujeme nezapečatené, potom je otvorený pre rozšírenie:

verejná nepečatená trieda Auto rozširuje Vozidlo implementuje službu {private final int numberOfSeats; public Car (int numberOfSeats, String registrationNumber) {super (registrationNumber); this.numberOfSeats = numberOfSeats; } public int getNumberOfSeats () {return numberOfSeats; } @Override public int getMaxServiceIntervalInMonths () {návrat 12; }}

3.4. Obmedzenia

Zapečatená trieda ukladá svojim povoleným podtriedam tri dôležité obmedzenia:

  1. Všetky povolené podtriedy musia patriť do rovnakého modulu ako zapečatená trieda.
  2. Každá povolená podtrieda musí výslovne rozširovať zapečatenú triedu.
  3. Každá povolená podtrieda musí definovať modifikátor: konečné, zapečatenéalebo nezapečatené.

4. Použitie

4.1. Tradičný spôsob

Pri zapečatení triedy umožňujeme kódu klienta jasne zdôvodniť všetky povolené podtriedy.

Tradičným spôsobom uvažovania o podtriede je použitie množiny keby-inak vyhlásenia a inštancia kontroly:

if (vehicle instanceof Car) {return ((Car) vehicle) .getNumberOfSeats (); } else if (vehicle instanceof Truck) {return ((Truck) vehicle) .getLoadCapacity (); } else {hodiť novú RuntimeException ("Neznáma inštancia vozidla"); }

4.2. Zhoda vzorov

Použitím zhody vzorov sa môžeme vyhnúť ďalšiemu obsadeniu triedy, stále však potrebujeme množinu if-iné Vyhlásenia:

if (vehicle instanceof Car car) {return car.getNumberOfSeats (); } else if (vozidlo instanceof Truck truck) {return truck.getLoadCapacity (); } else {hodiť novú RuntimeException ("Neznáma inštancia vozidla"); }

Pomocou if-iné sťažuje kompilátoru určiť, že sme pokryli všetky povolené podtriedy. Z tohto dôvodu hádžeme a RuntimeException.

V budúcich verziách Java bude kód klienta schopný používať a prepínač vyhlásenie namiesto if-iné (JEP 375).

Pomocou vzorov testovania typu bude kompilátor schopný skontrolovať, či je pokrytá každá povolená podtrieda. Už teda nebude potrebné a predvolené doložka / prípad.

4. Kompatibilita

Poďme sa teraz pozrieť na kompatibilitu zapečatených tried s ďalšími funkciami jazyka Java, ako sú záznamy a reflexné API.

4.1. Záznamy

Uzavreté triedy pracujú veľmi dobre so záznamami. Pretože záznamy sú implicitne konečné, zapečatená hierarchia je ešte stručnejšia. Skúsme náš príklad triedy prepísať pomocou záznamov:

verejné zapečatené rozhranie Vozidlo povoľuje Auto, Nákladné auto {String getRegistrationNumber (); } verejný záznam Car (int numberOfSeats, String registrationNumber) implementuje Vehicle {@Override public String getRegistrationNumber () {return registrationNumber; } public int getNumberOfSeats () {return numberOfSeats; }} verejný záznam Nákladné auto (int loadCapacity, String registrationNumber) implementuje Vozidlo {@Override public String getRegistrationNumber () {return registrationNumber; } public int getLoadCapacity () {return loadCapacity; }}

4.2. Odraz

Uzavreté triedy podporuje aj reflexné API, kde boli do API pridané dve verejné metódy java.lang.Class:

  • The je zapečatený metóda sa vracia pravda ak je daná trieda alebo rozhranie zapečatené.
  • Metóda povolené podtriedy vráti pole objektov predstavujúce všetky povolené podtriedy.

Tieto metódy môžeme použiť na vytvorenie tvrdení, ktoré sú založené na našom príklade:

Assertions.assertThat (truck.getClass (). IsSeals ()). IsEqualTo (false); Assertions.assertThat (truck.getClass (). GetSuperclass (). IsSeals ()). IsEqualTo (true); Assertions.assertThat (truck.getClass (). GetSuperclass (). AuthorizedSubclasses ()). Obsahuje (ClassDesc.of (truck.getClass (). GetCanonicalName ()));

5. Záver

V tomto článku sme preskúmali zapečatené triedy a rozhrania, funkciu ukážky v prostredí Java SE 15. Zaoberali sme sa vytváraním a používaním zapečatených tried a rozhraní, ako aj ich obmedzeniami a kompatibilitou s inými jazykovými funkciami.

V príkladoch sme sa zaoberali vytvorením zapečateného rozhrania a zapečatenej triedy, použitím zapečatenej triedy (s a bez porovnávania vzorov) a kompatibilitou zapečatených tried so záznamami a reflexným API.

Celý zdrojový kód je ako vždy k dispozícii na stránkach GitHub.


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