Zapečaćene klase i sučelja u Javi 15

1. Pregled

Izdanje Java SE 15 uvodi zatvorene razrede (JEP 360) kao značajku pregleda.

Ova se značajka odnosi na omogućavanje preciznije kontrole nasljeđivanja u Javi. Brtvljenje omogućuje klasama i sučeljima da definiraju svoje dopuštene podvrste.

Drugim riječima, klasa ili sučelje sada mogu definirati koje ga klase mogu implementirati ili proširiti. Korisna je značajka za modeliranje domena i povećanje sigurnosti knjižnica.

2. Motivacija

Hijerarhija klasa omogućuje nam ponovnu upotrebu koda putem nasljeđivanja. Međutim, hijerarhija klasa može imati i druge svrhe. Ponovna upotreba koda je sjajna, ali nije uvijek naš primarni cilj.

2.1. Mogućnosti modeliranja

Alternativna svrha hijerarhije klasa može biti modeliranje različitih mogućnosti koje postoje u domeni.

Kao primjer, zamislite poslovnu domenu koja radi samo s automobilima i kamionima, a ne s motociklima. Prilikom stvaranja Vozilo apstraktna klasa u Javi, trebali bismo dopustiti samo Automobil i Kamion klase kako bi ga produžili. Na taj način želimo osigurati da ne bude zlouporabe Vozilo sažetak klase unutar naše domene.

U ovom primjeru nas više zanima jasnoća rukovanja poznatim podklasama koda nego obrana od svih nepoznatih potklasa.

Prije verzije 15, Java je pretpostavljala da je ponovna upotreba koda uvijek cilj. Svaki se razred mogao proširiti s bilo kojim brojem podrazreda.

2.2. Paket-privatni pristup

U ranijim verzijama Java je pružala ograničene mogućnosti u području kontrole nasljeđivanja.

Završni razred ne može imati podrazred. Paket-privatna klasa može imati potklase samo u istom paketu.

Koristeći pristup paket-privatno, korisnici ne mogu pristupiti apstraktnoj klasi, a da im također ne dopuštaju da je prošire:

javna klasa Vozila {apstraktna statička klasa Vozilo {privatni konačni String registrationNumber; javno vozilo (String registrationNumber) {this.registrationNumber = registrationNumber; } javni String getRegistrationNumber () {return registrationNumber; }} javni statički konačni razred automobila produžuje vozilo {privatni konačni int brojOfSeats; javni automobil (int numberOfSeats, String registrationNumber) {super (registrationNumber); this.numberOfSeats = numberOfSeats; } javni int getNumberOfSeats () {povratak numberOfSeats; }} javni statički završni razred Kamion proširuje vozilo {private final int loadCapacity; javni kamion (int loadCapacity, String registrationNumber) {super (registrationNumber); this.loadCapacity = loadCapacity; } public int getLoadCapacity () {return loadCapacity; }}}

2.3. Superklasa dostupna, nije proširiva

Nadrazred koji je razvijen sa nizom svojih podrazreda trebao bi moći dokumentirati namjeravanu upotrebu, a ne ograničavati svoje podrazrede. Također, ograničene podrazrede ne bi trebale ograničiti pristup svojoj superklasi.

Stoga je glavna motivacija za zapečaćenim klasama imati mogućnost da superrazred bude široko dostupan, ali ne i široko proširiv.

3. Stvaranje

Zapečaćena značajka uvodi nekoliko novih modifikatora i klauzula u Javi: zapečaćeno, nezapečaćeno, i dozvole.

3.1. Zapečaćena sučelja

Da bismo zapečatili sučelje, možemo primijeniti zapečaćena modifikator svoje deklaracije. The dozvole klauzula tada navodi klase kojima je dopušteno implementirati zapečaćeno sučelje:

javno zapečaćeno sučelje Uslužne dozvole Automobil, Kamion {int getMaxServiceIntervalInMonths (); zadani int getMaxDistanceBetweenServicesInKilometers () {return 100000; }}

3.2. Zapečaćeni tečajevi

Slično sučeljima, klase možemo zapečatiti primjenom istih zapečaćena modifikator. The dozvole klauzulu treba definirati nakon bilo koje proteže se ili provodi klauzule:

javna sažetak zapečaćena klasa Dozvole za vozila Automobil, Kamion {zaštićen konačni String registrationNumber; javno vozilo (String registrationNumber) {this.registrationNumber = registrationNumber; } javni String getRegistrationNumber () {return registrationNumber; }}

Dopuštena podklasa mora definirati modifikator. Može se proglasiti konačni kako biste spriječili daljnja proširenja:

javni završni razred Kamion proširuje Vozila implementira uslugu {private final int loadCapacity; javni kamion (int loadCapacity, String registrationNumber) {super (registrationNumber); this.loadCapacity = loadCapacity; } public int getLoadCapacity () {return loadCapacity; } @Override public int getMaxServiceIntervalInMonths () {return 18; }}

Također se može prijaviti dopuštena potklasa zapečaćena. Međutim, ako to izjavimo nezapečaćeno, onda je otvoren za produženje:

javni neotvoreni razred automobila proširuje Usluge vozila {privatni konačni int brojOfSeats; javni automobil (int numberOfSeats, String registrationNumber) {super (registrationNumber); this.numberOfSeats = numberOfSeats; } javni int getNumberOfSeats () {povratak numberOfSeats; } @Override public int getMaxServiceIntervalInMonths () {return 12; }}

3.4. Ograničenja

Zapečaćena klasa nameće tri važna ograničenja svojim dopuštenim podrazredima:

  1. Sve dopuštene potklase moraju pripadati istom modulu kao i zatvorena klasa.
  2. Svaka dopuštena podrazred mora izričito proširiti zapečaćenu klasu.
  3. Svaka dopuštena podrazred mora definirati modifikator: konačni, zapečaćena, ili nezapečaćeno.

4. Upotreba

4.1. Tradicionalni način

Kada pečatimo klasu, omogućujemo klijentskom kodu da jasno obrazloži sve dopuštene potklase.

Tradicionalni način razmišljanja o podrazredu je korištenje skupa ako-drugo izjave i instanceof provjere:

if (vozilo instance of Car) {return ((Car) vozilo) .getNumberOfSeats (); } else if (vozilo instance Truck) {return ((Truck) vozilo) .getLoadCapacity (); } else {baciti novi RuntimeException ("Nepoznata instanca vozila"); }

4.2. Usklađivanje uzoraka

Primjenom podudaranja uzoraka možemo izbjeći dodatnu klasu, ali još uvijek trebamo skup if-ostalo izjave:

if (primjer vozila automobila) {return car.getNumberOfSeats (); } else if (primjer vozila kamiona) {return truck.getLoadCapacity (); } else {baciti novi RuntimeException ("Nepoznata instanca vozila"); }

Korištenjem if-ostalo otežava prevoditelju da utvrdi da smo pokrili sve dopuštene podrazrede. Iz tog razloga bacamo RuntimeException.

U budućim verzijama Jave, klijentski kôd moći će koristiti a sklopka izjava umjesto if-ostalo (JEP 375).

Korištenjem uzoraka za ispitivanje tipa, sastavljač će moći provjeriti je li obuhvaćena svaka dopuštena podklasa. Dakle, više neće biti potrebe za zadano klauzula / slučaj.

4. Kompatibilnost

Pogledajmo sada kompatibilnost zapečaćenih klasa s drugim značajkama Java jezika kao što su zapisi i API refleksije.

4.1. Zapisi

Zapečaćeni razredi vrlo dobro rade s zapisima. Budući da su zapisi implicitno konačni, zapečaćena hijerarhija još je sažetija. Pokušajmo prepisati naš primjer klase koristeći zapise:

javno zapečaćeno sučelje Dozvole za vozilo Automobil, Kamion {String getRegistrationNumber (); } javni zapis Car (int numberOfSeats, String registrationNumber) implementira Vehicle {@Override public String getRegistrationNumber () {return registrationNumber; } javni int getNumberOfSeats () {povratak numberOfSeats; }} javni zapis Kamion (int loadCapacity, String registrationNumber) implementira Vehicle {@Override public String getRegistrationNumber () {return registrationNumber; } public int getLoadCapacity () {return loadCapacity; }}

4.2. Odraz

Zapečaćene klase također podržava API refleksije, gdje su dvije javne metode dodane u java.lang.Class:

  • The jeZatvoreno metoda se vraća pravi ako je zadana klasa ili sučelje zapečaćeno.
  • Metoda dopuštene potklase vraća niz objekata koji predstavljaju sve dopuštene potklase.

Ove metode možemo koristiti za stvaranje tvrdnji koje se temelje na našem primjeru:

Assertions.assertThat (truck.getClass (). IsSeated ()). IsEqualTo (false); Assertions.assertThat (truck.getClass (). GetSuperclass (). IsSeated ()). IsEqualTo (true); Assertions.assertThat (truck.getClass (). GetSuperclass (). PermittedSubclasses ()) .contens (ClassDesc.of (truck.getClass (). GetCanonicalName ()));

5. Zaključak

U ovom smo članku istražili zapečaćene klase i sučelja, značajku pregleda u Javi SE 15. Obradili smo stvaranje i upotrebu zapečaćenih klasa i sučelja, kao i njihova ograničenja i kompatibilnost s drugim jezičnim značajkama.

U primjerima smo pokrili stvaranje zapečaćenog sučelja i zapečaćene klase, upotrebu zapečaćene klase (sa i bez podudaranja uzoraka) i kompatibilnost zapečaćenih klasa sa zapisima i API-jem refleksije.

Kao i uvijek, cjeloviti izvorni kod dostupan je na GitHub-u.


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