Zárt osztályok és interfészek a Java 15-ben

1. Áttekintés

A Java SE 15 bemutatja a lezárt osztályokat (JEP 360) előnézetként.

Ez a funkció arról szól, hogy lehetővé tegye a finomabb szemléletű öröklésszabályozást a Java-ban. A tömítés lehetővé teszi az osztályok és interfészek számára, hogy meghatározzák megengedett altípusaikat.

Más szavakkal, egy osztály vagy egy interfész most meghatározhatja, hogy mely osztályok tudják megvalósítani vagy kibővíteni. Hasznos szolgáltatás a tartománymodellezéshez és a könyvtárak biztonságának növeléséhez.

2. Motiváció

Az osztályhierarchia lehetővé teszi számunkra a kód öröklés útján történő újrafelhasználását. Az osztályhierarchiának azonban más céljai is lehetnek. A kód újrafelhasználása nagyszerű, de nem mindig ez az elsődleges célunk.

2.1. Modellezési lehetőségek

Az osztályhierarchia alternatív célja lehet egy tartományban létező különféle lehetőségek modellezése.

Példaként képzeljünk el egy üzleti területet, amely csak személygépkocsikkal és teherautókkal működik, nem motorkerékpárokkal. A Jármű absztrakt osztály Java-ban, csak engedélyeznünk kell Autó és Kamion osztályok meghosszabbítására. Ily módon szeretnénk biztosítani, hogy a programmal ne éljenek vissza Jármű absztrakt osztály a domainünkön belül.

Ebben a példában inkább az ismert alosztályok kódkezelésének egyértelműsége érdekel, mint az összes ismeretlen alosztály elleni védekezés.

A 15. verzió előtt a Java feltételezte, hogy a kód újrafelhasználása mindig cél. Minden osztály tetszőleges számú alosztályval bővíthető volt.

2.2. A csomag-magán megközelítés

A korábbi verziókban a Java korlátozott lehetőségeket biztosított az öröklésszabályozás területén.

Egy utolsó osztálynak nem lehetnek alosztályai. A package-private osztálynak csak ugyanabban a csomagban lehetnek alosztályai.

A csomag-privát megközelítés használatával a felhasználók nem férhetnek hozzá az absztrakt osztályhoz, anélkül hogy engedélyeznék annak kibővítését:

public class Járművek {absztrakt statikus osztály Jármű {private final String registrationNumber; public Vehicle (String registrationNumber) {this.registrationNumber = regisztrációs szám; } public String getRegistrationNumber () {return registrationNumber; }} public static final class Autó meghosszabbítja Jármű {private final int numberOfSeats; public Car (int numberOfSeats, String registrationNumber) {szuper (registrationNumber); this.numberOfSeats = numberOfSeats; } public int getNumberOfSeats () {return numberOfSeats; }} public static final class Truck meghosszabbítja a járművet {private final int loadCapacity; public Truck (int loadCapacity, String registrationNumber) {szuper (regisztrációs szám); this.loadCapacity = loadCapacity; } public int getLoadCapacity () {return loadCapacity; }}}

2.3. Szuperosztály elérhető, nem nyújtható

Az alosztályok halmazával kifejlesztett szuperosztálynak képesnek kell lennie a rendeltetésszerű használat dokumentálására, nem korlátozhatja az alosztályokat. A korlátozott alosztályok nem korlátozhatják a szuperosztály hozzáférhetőségét.

Így a zárt osztályok mögött az a fő motiváció, hogy lehetősége legyen arra, hogy egy szuperosztály széles körben elérhető legyen, de ne legyen széles körben kibővíthető.

3. Teremtés

A lezárt szolgáltatás bevezet néhány új módosítót és záradékot a Java-ban: lezárt, nem lezárt, és engedélyeket.

3.1. Zárt interfészek

Egy felület lezárásához alkalmazhatjuk a zárt nyilatkozatának módosítója. A engedélyeket A záradék ezután meghatározza azokat az osztályokat, amelyek engedélyezettek a lezárt interfész megvalósításához:

nyilvános zárt felület A szolgáltatás engedélyezi a kocsit, teherautót {int getMaxServiceIntervalInMonths (); alapértelmezett int getMaxDistanceBetweenServicesInKilometers () {return 100000; }}

3.2. Zárt osztályok

Az interfészekhez hasonlóan ugyanezekkel az osztályokkal is lezárhatjuk az osztályokat zárt módosító. A engedélyeket záradékot bármelyik után meg kell határozni kiterjed vagy megvalósítja záradékok:

nyilvános absztrakt lezárt osztály Járműengedélyek Autó, Teherautó {védett végső String registrationNumber; public Vehicle (String registrationNumber) {this.registrationNumber = regisztrációs szám; } public String getRegistrationNumber () {return registrationNumber; }}

Az engedélyezett alosztálynak meg kell határoznia egy módosítót. Lehet kijelenteni végső a további meghosszabbítások megakadályozása érdekében:

nyilvános végosztály teherautó meghosszabbítja a gépjárművet Szolgáltatás {private final int loadCapacity; public Truck (int loadCapacity, String registrationNumber) {szuper (regisztrációs szám); this.loadCapacity = loadCapacity; } public int getLoadCapacity () {return loadCapacity; } @Orride public int getMaxServiceIntervalInMonths () {return 18; }}

Megengedett alosztályt is deklarálhatunk zárt. Ha azonban kijelentjük lezáratlan, akkor nyitva áll a kiterjesztésre:

nyilvános, nem lezárt osztály Autó meghosszabbítja a járművet Szolgáltatás {private final int numberOfSeats; public Car (int numberOfSeats, String registrationNumber) {szuper (registrationNumber); this.numberOfSeats = numberOfSeats; } public int getNumberOfSeats () {return numberOfSeats; } @Orride public int getMaxServiceIntervalInMonths () {return 12; }}

3.4. Korlátok

A lezárt osztály három fontos korlátozást ír elő megengedett alosztályain:

  1. Minden megengedett alosztálynak ugyanabba a modulba kell tartoznia, mint a lezárt osztály.
  2. Minden megengedett alosztálynak kifejezetten ki kell terjesztenie a lezárt osztályt.
  3. Minden megengedett alosztálynak meg kell határoznia egy módosítót: végső, zárt, vagy lezáratlan.

4. Használat

4.1. A hagyományos út

Egy osztály lezárásakor lehetővé tesszük, hogy az ügyfélkód egyértelműen indokolja az összes engedélyezett alosztályt.

Az alosztály okoskodásának hagyományos módja a ha más nyilatkozatok és Például az ellenőrzések:

if (jármű példánya autó) {visszatérés ((autó) jármű) .getNumberOfSeats (); } else if (kamionjármű példánya) {visszatérés ((teherautó) jármű) .getLoadCapacity (); } else {dob új RuntimeException ("Jármű ismeretlen példánya"); }

4.2. Mintaillesztés

A mintaillesztés alkalmazásával elkerülhetjük a további osztálybaosztást, de mégis szükségünk van egy i készletref-más nyilatkozatok:

if (jármű példánya Autó autó) {visszatérő autó.getNumberOfSeats (); } else if (kamion teherautó példánya) {return truck.getLoadCapacity (); } else {dob új RuntimeException ("Jármű ismeretlen példánya"); }

Az if-más megnehezíti a fordító számára annak megállapítását, hogy az összes megengedett alosztályt lefedtük. Ezért dobunk egy RuntimeException.

A Java jövőbeni verzióiban az ügyfélkód képes lesz használni a kapcsoló állítás i helyettf-más (JEP 375.).

Típusvizsgálati minták használatával a fordító ellenőrizni tudja, hogy minden engedélyezett alosztály lefedett-e. Így már nem lesz szükség a alapértelmezett záradék / eset.

4. Kompatibilitás

Vizsgáljuk meg a lezárt osztályok kompatibilitását más Java nyelvi funkciókkal, például a rekordokkal és a reflexiós API-val.

4.1. Rekordok

A lezárt osztályok nagyon jól működnek a nyilvántartásokkal. Mivel a nyilvántartások hallgatólagosan véglegesek, a lezárt hierarchia még tömörebb. Próbáljuk meg átírni osztálypéldánkat rekordok segítségével:

nyilvános, lezárt felület Jármű engedélyezi a kocsit, teherautót {String getRegistrationNumber (); } nyilvános nyilvántartás Autó (int numberOfSeats, String registrationNumber) megvalósítja Jármű {@Orride public String getRegistrationNumber () {return registrationNumber; } public int getNumberOfSeats () {return numberOfSeats; }} nyilvános nyilvántartás Teherautó (int loadCapacity, String registrationNumber) megvalósítja a járművet {@Override public String getRegistrationNumber () {return registrationNumber; } public int getLoadCapacity () {return loadCapacity; }}

4.2. Visszaverődés

A lezárt osztályokat a reflexió API is támogatja, ahol két nyilvános módszert adtak a java.lang.Osztály:

  • A isSealed metódus visszatér igaz ha az adott osztály vagy interfész le van zárva.
  • Módszer engedélyezett alosztályok az összes megengedett alosztályt képviselő objektumok tömbjét adja vissza.

Ezeket a módszereket felhasználhatjuk olyan állítások létrehozására, amelyek a példánkon alapulnak:

Assertions.assertThat (truck.getClass (). IsSealed ()). IsEqualTo (hamis); Assertions.assertThat (truck.getClass (). GetSuperclass (). IsSealed ()). IsEqualTo (true); Assertions.assertThat (truck.getClass (). GetSuperclass (). AllowedSubclasses ()) .contains (ClassDesc.of (truck.getClass (). GetCanonicalName ()));

5. Következtetés

Ebben a cikkben feltártuk a lezárt osztályokat és interfészeket, a Java SE 15 előnézeti funkcióját. Kitértünk a lezárt osztályok és interfészek létrehozására és használatára, valamint azok kényszerére és kompatibilitására más nyelvi jellemzőkkel.

A példákban kitértünk egy lezárt felület és egy lezárt osztály létrehozására, a lezárt osztály használatára (mintaillesztéssel és anélkül), valamint a lezárt osztályok kompatibilitására a rekordokkal és a reflexiós API-val.

Mint mindig, a teljes forráskód elérhető a GitHubon.