Enums kiterjesztése a Java-ban

1. Áttekintés

A Java 5-ben bevezetett enum típus egy speciális adattípus, amely konstansok csoportját képviseli.

Az enumok használatával meghatározhatjuk és felhasználhatjuk az állandókat a típusbiztonság módjára. A fordítási idő ellenőrzését hozza az állandókhoz.

Továbbá lehetővé teszi számunkra az állandók használatát a kapcsolószekrény nyilatkozat.

Ebben az oktatóanyagban megvitatjuk az enums bővítését a Java-ban, például új állandó értékek és új funkciók hozzáadásával.

2. Enums és öröklés

Amikor bővíteni akarunk egy Java osztályt, akkor általában létrehozunk egy alosztályt. A Java-ban az enumok is osztályok.

Ebben a szakaszban nézzük meg, hogy örökölhetünk-e egy enumot, mint a szokásos Java osztályoknál.

2.1. Enum típus kiterjesztése

Először nézzünk meg egy példát, hogy gyorsan megértsük a problémát:

public enum BasicStringOperation {TRIM ("Első és záró szóközök eltávolítása."), TO_UPPER ("Minden karakter nagybetűvé változtatása."), REVERSE ("Az adott karakterlánc megfordítása."); privát karakterlánc leírása; // konstruktor és getter}

Amint a fenti kód mutatja, van egy enumunk BasicStringOperation amely három alap string műveletet tartalmaz.

Tegyük fel, hogy hozzá szeretnénk adni néhány kiterjesztést az enumhoz, például MD5_ENCODE és BASE64_ENCODE. Előállhatunk ezzel az egyszerű megoldással:

public enum Az ExtendedStringOperation kiterjeszti a BasicStringOperation {MD5_ENCODE ("Az adott karakterlánc kódolása az MD5 algoritmus használatával."), BASE64_ENCODE ("Az adott karakterlánc kódolása a BASE64 algoritmus használatával."); privát karakterlánc leírása; // konstruktor és getter}

Amikor azonban megpróbáljuk lefordítani az osztályt, látni fogjuk a fordító hibáját:

Nem örökölhető az enum BasicStringOperation-ból

2.2. Az örökség nem engedélyezett az Enums számára

Nézzük meg, miért kaptuk a fordító hibánkat.

Amikor összeállítunk egy enumot, a Java fordító varázslatot tesz rá:

  • Az enumot az absztrakt osztály egyik alosztályává változtatja java.lang.Enum
  • Összeállítja az enumot a végső osztály

Például, ha szétszedjük az összeállítottakat BasicStringOperation enum felhasználásával javap, látni fogjuk, hogy a java.lang.Enum:

$ javap BasicStringOperation public final class com.baeldung.enums.extendenum.BasicStringOperation kiterjeszti a java.lang.Enum {public static final com.baeldung.enums.extendenum.BasicStringOperation TRIM; public static final com.baeldung.enums.extendenum.BasicStringOperation TO_UPPER; public static final com.baeldung.enums.extendenum.BasicStringOperation REVERSE; ...} 

Mint tudjuk, nem örökölhetjük a végső osztály Java-ban. Sőt, még ha létrehozhatnánk is a ExtendedStringOperation enum örökölni BasicStringOperation, a mi ExtendedStringOperation az enum két osztályt bővítene: BasicStringOperation és java.lang.Enum. Vagyis többszörös öröklési szituációvá válna, amelyet a Java nem támogat.

3. Emuláljon kiterjeszthető számokat interfészekkel

Megtudtuk, hogy nem hozhatunk létre egy meglévő enum alosztályát. Az interfész azonban bővíthető. Ebből kifolyólag, interfész megvalósításával kiterjeszthető enumokat utánozhatunk.

3.1. Emulálja az állandók kiterjesztését

Hogy gyorsan megértsük ezt a technikát, nézzük meg, hogyan kell utánozni a kiterjesztésünket BasicStringOperation enum van MD5_ENCODE és BASE64_ENCODE tevékenységek.

Először hozzunk létre egy felületStringOperation:

nyilvános felület StringOperation {String getDescription (); } 

Ezután mindkét enumot a fenti felület megvalósítására késztetjük:

public enum A BasicStringOperation végrehajtja a StringOperation {TRIM ("Első és záró szóközök eltávolítása."), TO_UPPER ("Minden karakter nagybetűvé változtatása."), REVERSE ("Az adott karakterlánc megfordítása."); privát karakterlánc leírása; // konstruktor és a getter felülírja} public enum Az ExtendedStringOperation végrehajtja a StringOperation {MD5_ENCODE ("Az adott karakterlánc kódolása az MD5 algoritmus használatával."), BASE64_ENCODE ("Az adott karakterlánc kódolása a BASE64 algoritmus segítségével."); privát karakterlánc leírása; // konstruktor és getter felülbírálása} 

Végül nézzük meg, hogyan kell utánozni egy bővíthetőt BasicStringOperation enum.

Tegyük fel, hogy alkalmazásunkban van egy módszer a leírás megszerzésére BasicStringOperation enum:

public class Alkalmazás {public String getOperationDescription (BasicStringOperation stringOperation) {return stringOperation.getDescription (); }} 

Most megváltoztathatjuk a paramétertípust BasicStringOperation az interfész típusába StringOperation hogy a módszer elfogadja mindkét enum példányait:

public String getOperationDescription (StringOperation stringOperation) {return stringOperation.getDescription (); }

3.2. A funkciók bővítése

Láttuk, hogyan lehet utánozni az enumok kiterjedő állandóit interfészekkel.

Ezenkívül az interfészhez hozzáadhatunk módszereket az enumok funkcióinak bővítésére.

Például ki akarjuk terjeszteni StringOperation enums, hogy minden konstans valóban alkalmazhassa a műveletet egy adott karakterláncra:

public class Alkalmazás {public String ApplyOperation (StringOperation művelet, String bevitel) {return operation.apply (input); } // ...} 

Ennek eléréséhez először tegyük hozzá a alkalmaz() metódus az interfészhez:

nyilvános felület StringOperation {String getDescription (); Karakterlánc alkalmazása (String input); } 

Ezután mindegyiket engedtük StringOperation enum alkalmazza ezt a módszert:

public enum A BasicStringOperation végrehajtja a StringOperation {TRIM ("Első és záró terek eltávolítása.") {@Orride public String Apply (String input) {return input.trim (); }}, TO_UPPER ("Az összes karakter nagybetűvé változtatása.") {@ Nyilvános karakterlánc felülírása érvényes (karakterlánc bemenet) {return input.toUpperCase (); }}, REVERSE ("A megadott karaktersorozat megfordítása.") {@Orride public String Apply (String input) {return new StringBuilder (input) .reverse (). ToString (); }}; // ...} public enum ExtendedStringOperation végrehajtja a StringOperation {MD5_ENCODE ("Az adott karakterlánc kódolása az MD5 algoritmus használatával.") {@Orride public String Apply (String input) {return DigestUtils.md5Hex (input); }}, BASE64_ENCODE ("Az adott karakterlánc kódolása a BASE64 algoritmus használatával.") {@Orride public String Apply (String input) {return new String (new Base64 (). Encode (input.getBytes ())); }}; // ...} 

Egy vizsgálati módszer bizonyítja, hogy ez a megközelítés a várt módon működik:

@Test public void givenAStringAndOperation_whenApplyOperation_thenGetExpectedResult () {String input = "hello"; Karakterlánc vártToUpper = "HELLO"; Karakterlánc várhatóReverse = "olleh"; String várhatóTrim = "hello"; String várhatóBase64 = "IGhlbGxv"; String várhatóMd5 = "292a5af68d31c10e31ad449bd8f51263"; assertEquals (várhatóTrim, app.applyOperation (BasicStringOperation.TRIM, input)); assertEquals (várhatóToUpper, app.applyOperation (BasicStringOperation.TO_UPPER, input)); assertEquals (várhatóReverse, app.applyOperation (BasicStringOperation.REVERSE, input)); assertEquals (várhatóBase64, app.applyOperation (ExtendedStringOperation.BASE64_ENCODE, input)); assertEquals (várhatóMd5, app.applyOperation (ExtendedStringOperation.MD5_ENCODE, input)); } 

4. Enum kiterjesztése a kód megváltoztatása nélkül

Megtanultuk, hogyan lehet kiterjeszteni az enumot interfészek megvalósításával.

Azonban néha meg akarjuk bővíteni az enum funkcióit anélkül, hogy módosítanánk. Például egy harmadik fél könyvtárából szeretnénk kiterjeszteni egy enumot.

4.1. Az Enum konstansok és az interfész megvalósítások társítása

Először vessünk egy pillantást egy enum példára:

public enum ImmutableOperation {REMOVE_WHITESPACES, TO_LOWER, INVERT_CASE} 

Tegyük fel, hogy az enum egy külső könyvtárból származik, ezért nem tudjuk megváltoztatni a kódot.

Most, a mi Alkalmazás osztályban szeretnénk egy módszert alkalmazni az adott műveletet a bemeneti karakterláncra:

public String applyImmutableOperation (ImmutableOperation művelet, String bevitel) {...}

Mivel nem tudjuk megváltoztatni az enum kódot, tudjuk használni EnumMap társítani az enum állandókat és a szükséges megvalósításokat.

Először hozzunk létre egy felületet:

nyilvános felület Operátor {String Apply (String input); } 

Ezután elkészítjük az enum konstansok és a Operátor megvalósítások egy EnumMap:

public class Alkalmazás {private static final Map OPERATION_MAP; statikus {OPERATION_MAP = új EnumMap (ImmutableOperation.class); OPERATION_MAP.put (ImmutableOperation.TO_LOWER, String :: toLowerCase); OPERATION_MAP.put (ImmutableOperation.INVERT_CASE, StringUtils :: swapCase); OPERATION_MAP.put (ImmutableOperation.REMOVE_WHITESPACES, input -> input.replaceAll ("\ s", "")); } public String applyImmutableOperation (ImmutableOperation művelet, String bemenet) {return operationMap.get (művelet) .apply (bemenet); }

Ily módon a mi ApplyImmutableOperation () A módszer a megfelelő műveletet alkalmazhatja az adott bemeneti karakterláncra:

@Test public void givenAStringAndImmutableOperation_whenApplyOperation_thenGetExpectedResult () {String input = "He ll O"; String várhatóToLower = "he ll o"; String várhatóRmWhitespace = "HellO"; String várhatóInvertCase = "hE LL o"; assertEquals (várhatóToLower, app.applyImmutableOperation (ImmutableOperation.TO_LOWER, input)); assertEquals (várhatóRmWhitespace, app.applyImmutableOperation (ImmutableOperation.REMOVE_WHITESPACES, bemenet)); assertEquals (várhatóInvertCase, app.applyImmutableOperation (ImmutableOperation.INVERT_CASE, input)); } 

4.2. A EnumMap Tárgy

Most, ha az enum külső könyvtárból származik, nem tudjuk, hogy megváltozott-e vagy sem, például új konstansok hozzáadásával az enumhoz. Ebben az esetben, ha nem változtatunk a EnumMap hogy tartalmazzák az új enum értéket, a mi EnumMap megközelítés problémába ütközhet, ha az újonnan hozzáadott enum konstans átkerül alkalmazásunkhoz.

Ennek elkerülése érdekében érvényesíthetjük a EnumMap inicializálása után ellenőrizze, hogy tartalmazza-e az összes enumállandót:

statikus {OPERATION_MAP = új EnumMap (ImmutableOperation.class); OPERATION_MAP.put (ImmutableOperation.TO_LOWER, String :: toLowerCase); OPERATION_MAP.put (ImmutableOperation.INVERT_CASE, StringUtils :: swapCase); // Az ImmutableOperation.REMOVE_WHITESPACES nincs feltérképezve, ha (Arrays.stream (ImmutableOperation.values ​​()). AnyMatch (it ->! OPERATION_MAP.containsKey (it))) {dob új IllegalStateException ("Feltáratlan enum konstans megtalálva!"); }} 

Amint a fenti kód mutatja, ha van állandó a -tól ImmutableOperation nincs feltérképezve, an IllegalStateException dobni fogják. Mivel validálásunk a statikus Blokk, IllegalStateException oka lesz ExceptionInInitializerError:

@Test public void givenUnmappedImmutableOperationValue_whenAppStarts_thenGetException () {Throwable dobható = assertThrows (ExceptionInInitializerError.class, () -> {ApplicationWithEx appEx = új ApplicationWithEx ();}); assertTrue (dobható.getCause () IllegalStateException példány); } 

Így, ha az alkalmazás nem indul el az említett hibával és okkal, akkor még egyszer ellenőriznünk kell a ImmutableOperation hogy minden állandót feltérképezzenek.

5. Következtetés

Az enum egy speciális adattípus a Java-ban. Ebben a cikkben megvitattuk, hogy az enum miért nem támogatja az öröklést. Ezt követően azzal foglalkoztunk, hogyan lehet utánozni a bővíthető enumokat az interfészekkel.

Megtanultuk azt is, hogyan lehet kibővíteni az enum funkcióit anélkül, hogy megváltoztatnánk.

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


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