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
enumpertenece 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
enumeradoestá 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