En una aplicación Java que estoy trabajando, tengo una serie de enumeraciones, que llegó a tener una estática fromString
método en ellos para convertir una cadena a su valor de enumeración real.
Por lo tanto, pensé que podría tener una clase de "base" de la que todos mis enumeraciones pueden extender sin tener que repetir ese código todo el tiempo. Desde enumeraciones no pueden extender las clases, he planeado hacer es que yo podría ser capaz de hacerlo a través de una interfaz en su lugar.
Lo que he es el siguiente:
public interface IBaseEnum {
String enumVal = null;
public static <T extends Enum<T> & IBaseEnum> Enum<T> fromString(String strVal) {
if (strVal == null) return null;
// T.values() has error because T is not recognised to have the method values()
for (T myEnum : T.values()) {
if (myEnum.enumVal.equals(strVal.toUpperCase())) {
return myEnum;
}
}
return null;
}
}
Y luego, para heredar ese método estático, voy a poner en práctica IBaseEnum
en mi Enum real:
public enum Colour implements IBaseEnum {
Red("red");
//...
}
Sin embargo, estoy teniendo problemas con los tipos de IBaseEnum
. La línea T.values()
está teniendo error debido a que el tipo genérico T
no se puede hacer referencia de nuevo a la propia enumeración y por lo que se queja de que el método values()
no se encuentra.
¿Es esta la manera correcta de funcionalidades Heredar enumeración? De lo contrario, ¿cómo puedo heredar métodos en las enumeraciones de modo que yo no tengo que copiar / pegar y repetir un mismo conjunto de métodos en cada enumeraciones individuales?
Hay algunas razones por las que su código no funcionaría, de los cuales debo mencionar:
String enumVal = null;
:IBaseEnum
Siendo una interfaz,numVal
obtiene los implícitospublic
,static
yfinal
modificadores. Sin embargo, usted tiene la intenciónenumVal
de ser una propiedad de instancia.T.values()
: Por supuesto esto no compila. Pero incluso si pudiera (o tenías la instancia de clase), todavía no sería capaz de hacer esta dinámica. Los métodos estáticos son recogidos en tiempo de compilación. La única manera (que yo sepa) para hacer que funcione de forma dinámica sería el uso de la reflexión, de pasar curso de la clase de objeto de la enumeración.
Porque quiere ser capaz de llamar Color.fromString(...)
, no tiene más remedio que declarar esto como un método estático en cada clase de enumeración. Dicho esto, creo que lo máximo que puede volver a utilizar desde su lógica es el código de búsqueda (una vez más, que de no ser que utilizan la reflexión).
Para volver a utilizar la lógica de búsqueda, puede cambiar el contrato de IBaseEnum
hacerla declarar un método que que devuelve el enumVal
valor. Además de eso, el values()
método puede ser invocado por las clases de enumeración mismos. Esto es lo que puede verse como:
interface IBaseEnum {
String enumVal();
public static <T extends Enum<T> & IBaseEnum> T
fromString(String strVal, T[] values) {
if (strVal == null)
return null;
for (T myEnum : values) {
if (myEnum.enumVal().equalsIgnoreCase(strVal)) {
return myEnum;
}
}
return null;
}
}
Y que dará lugar a una clase de enumeración como la siguiente:
enum Colour implements IBaseEnum {
VAL1("string")
;
private final String val;
Colour(String v) {
this.val = v;
}
@Override
public String enumVal() {
return this.val;
}
public static Colour fromString(String s) {
return IBaseEnum.fromString(s, values());
}
}
Recuerde: Si enumVal()
tiene la intención de devolver sólo el literal de enumeración, a continuación, usted puede deshacerse de toda esta complejidad sólo por el uso del valueOf
método disponible en todas las enumeraciones. Sólo haga esto si la comparación de los valores de las necesidades de la lógica personalizada.