Extender enumeraciones en Java
Este tutorial demuestra cómo extender la funcionalidad enumeración
en Java.
Extender enumeración
en Java
Podemos considerar enum
como una especie de magia del compilador porque, en el código byte
, el enum
se representa como una clase con varios miembros estáticos
y se hereda del resumen java.lang.Enum
.
Es la razón por la que enumeración
no puede extenderse a ninguna otra clase o enumeración
. Como no podemos extender enumeración
en Java, tampoco es posible que ninguna clase extienda una enumeración
. Aprendamos usando el siguiente código de ejemplo y veamos qué sucede.
Código de ejemplo:
package delftstack;
enum Cars { Audi, BMW, Marcedes }
public class Example extends Cars {
public static void main(String... args) {}
}
El código anterior tiene una enumeración
llamada Coches
, y la clase Ejemplo
está tratando de extenderla. Ver salida:
/Example.java:5: error: cannot inherit from final Cars
public class Example extends Cars {
^
/Example.java:5: error: enum types are not extensible
public class Example extends Cars {
^
2 errors
Como podemos ver, la clase no puede extender el enum
. Entonces, si es imposible extender la enumeración
, ¿podemos aún extender su funcionalidad?
La funcionalidad se puede definir como los métodos implementados en el enum
. Por ejemplo, el enum
Cars
del código anterior puede declarar métodos abstractos para cada miembro; ver el ejemplo:
enum Cars {
Audi {
@Override
public void drive() {}
},
BMW {
@Override
public void drive() {}
},
Mercedes {
@Override
public void drive() {}
},
;
public abstract void drive();
}
Como podemos ver, cada miembro puede anular el método drive()
. Pero desafortunadamente, no siempre es posible crear métodos en enum
porque:
- Si el
enum
pertenece a una biblioteca de terceros oa otro equipo, no permitirá la implementación de métodos abstractos. - Si pertenece al módulo que no tiene la dependencia requerida para el método
drive()
. - Si el
enumerado
está sobrecargado con otras funciones y datos, será ilegible.
Se proporcionan algunas soluciones que pueden resolver estos problemas y ampliar la funcionalidad de enum
en Java.
Solución 1: espejo enum
en Java
Como sugiere el nombre, necesitamos crear otra enumeración
con los mismos datos. Esa nueva enumeración
también implementará el método drive()
, por lo que ahora tenemos dos enumeraciones:
Código de ejemplo para enum Cars
:
enum Cars {
Audi {
@Override
public void drive() {}
},
BMW {
@Override
public void drive() {}
},
Mercedes {
@Override
public void drive() {}
},
;
public abstract void drive();
}
Código de ejemplo para enum DriveCars
:
enum DriveCars {
Audi {
@Override
public void drive() {}
},
BMW {
@Override
public void drive() {}
},
Mercedes {
@Override
public void drive() {}
},
;
public abstract void drive();
}
El segundo enumerado
es el espejo del primero. Ahora podemos usar ambas enumeraciones extendiendo la funcionalidad; necesitamos usar métodos integrados enum
que son name()
y valueof()
.
Vea el siguiente ejemplo de cómo usarlo:
Cars cars = ... DriveCars.valueOf(cars.name()).drive();
El código anterior muestra cómo se usa la funcionalidad enum Cars
en enum DriveCars
. Lo que significa que la funcionalidad se amplía.
El método name()
en el código anterior es final
, que no se puede anular, y el compilador generará el método valueOf
. Ambos métodos encajan bien entre sí si no hay ningún error funcional en la operación extendida.
Hay un problema con el código anterior si se cambia el enum Cars
, el enum DriveCars
no tendrá ninguna idea, y causará la falla del truco name
y valueof
. Para resolver este problema, debemos informar a DriveCars
que su espejo principal es Cars
.
Para eso, podemos usar un inicializador estático
para comparar DriveCars
y Cars
, que arrojará la excepción si ambas enumeraciones no coinciden. Aquí hay un ejemplo de eso de la biblioteca enumus:
enum DriveCars {
....static { Mirror.of(Cars.class); }
}
La clase de utilidad verificará si ambas enumeraciones coinciden o no. Este método validará el truco name()
y valueOf()
.
Solución 2: Mapa enum
en Java
Si no desea crear otra enumeración
que contenga solo un método. En este caso, podemos usar interfaz
en lugar de enum
; vea el ejemplo a continuación:
public interface Driver {
void drive();
}
Ahora, para usar esta interfaz Drive
con la enumeración Cars
, podemos crear un mapeo entre ellos. Aquí está el ejemplo para el mapa:
Map<Cars, Driver> drivers = new EnumMap<>(Cars.class) {
{
put(Audi, new Driver() {
@Override
public void driver() {}
}) put(BMW, new Driver() {
@Override
public void driver() {}
}) put(Mercedes, new Driver() {
@Override
public void driver() {}
})
}
}
Ahora, para usarlos, use este simple código:
drivers.get(Cars).drive();
El EnumMap
utilizado en el código anterior garantizará que cada miembro enum
aparecerá solo una vez, pero no garantiza una entrada para cada miembro.
Podemos comprobar que el tamaño del mapa es igual al número de miembros de las enumeraciones:
drivers.size() == Cars.values().length
La biblioteca enumus también proporciona una utilidad para este caso: si el mapa no se ajusta a los Cars
, lanzará la IllegalStateException
. Aquí está la utilidad:
EnumMapValidator.validateValues(Cars.class, map, "Cars map");
Ambos métodos anteriores muestran cómo hacer que las enumeraciones sean poderosas al extender su funcionalidad. Aunque es imposible extender directamente una enumeración
, podemos usar estos trucos para ampliar sus funcionalidades.
Sheeraz is a Doctorate fellow in Computer Science at Northwestern Polytechnical University, Xian, China. He has 7 years of Software Development experience in AI, Web, Database, and Desktop technologies. He writes tutorials in Java, PHP, Python, GoLang, R, etc., to help beginners learn the field of Computer Science.
LinkedIn Facebook