2009-04-07 15 views
11

En Java, un Enum puede hacer las grandes cosas que hacen los Enum, pero también puede tener métodos (comportamiento y lógica). ¿Qué ventaja tiene eso sobre usar una clase usando una enumeración? Ejemplos simples para ilustrar el punto también serían bienvenidos.Java Enums puede tener comportamiento?

Respuesta

14

Aquí está un ejemplo sencillo:

enum RoundingMode { 
    UP { 
     public double round(double d) { 
      return Math.ceil(d); 
     } 
    }, 
    DOWN { 
     public double round(double d) { 
      return Math.floor(d); 
     } 
    }; 

    public abstract double round(double d); 
} 
+0

¿Cómo usaría esto en el código? ¿Acabo de hacer esto? double foo = RoundingMode.round (20.3); ¿O ampliaría la enumeración a la enumeración de hijo? Me abandona el método abstracto. – Dave

+0

El método abstracto es anulado por las clases anidadas usadas por UP y DOWN. Lo usarías en un código como este: double doMath (RoundMode m, double x, double y) {double d; ... d = m.round (d); ... devolver d; } Pasarías en RoundingMode.UP o RoundingMode.DOWN como el primer parámetro. –

+0

¡Gracias! No estoy seguro de cómo me siento al respecto, pero ahora lo entiendo;) – Dave

6

No estoy muy seguro de dónde encaja el título de la pregunta con el resto. Sí, las enumeraciones Java tienen comportamiento. También pueden tener estado, aunque en realidad debería ser realmente estado inmutable. (La idea de un valor enum mutable es bastante aterradora IMO.)

Una enumeración en Java es básicamente un conjunto fijo de objetos. El beneficio es que usted sabe que si tiene una referencia de ese tipo, es siempre ya sea null o uno de los conjuntos conocidos.

Personalmente, me encantan las enums de Java y deseo que C# las tuviera también; están mucho más orientadas a objetos que las enumeraciones de C# que son básicamente "números con nombre". Hay algunos "errores" en términos de orden de inicialización, pero en general son fabulosos.

+0

¿No puedes emular las enumeraciones de Java con clases de C#? –

+0

@Vilx: por supuesto que puedes. Antes de Java 5, podría escribir sus propias clases para hacer objetos enum de tipo seguro. (Bueno, todavía puedes, por supuesto, no hay mucho de un punto.) – Eddie

+0

Vilx: Puedes, pero es un poco desagradable. Básicamente se usa un tipo base abstracto con un constructor privado, y se deriva de él con tipos * anidados * que pueden llamar al constructor privado. –

1

En nuestro proyecto, usamos Enums para algunas cosas, pero quizás lo más destacado para i18n, cada parte del texto mostrado tiene un Enum. La clase Enum tiene un método de devolución de cadena que inspecciona la configuración regional que se está utilizando y selecciona la traducción correcta de una colección de traducciones en tiempo de ejecución.

Esto tiene un doble propósito: obtiene el código completo de su IDE y nunca se olvida de traducir una cadena.

El uso es muy simple, hasta el punto de que es casi rendundant para dar un ejemplo, pero aquí es cómo se puede utilizar la traducción-enumeración

System.out.println(Translations.GREET_PERSON.trans()+" "+user.getName()); 

O, si se quiere ser de lujo, tiene la Enum aceptar los argumentos, que, con un poco de manipulación de cadenas magia, pueden insertar en una posición marcada en la cadena de traducciones

System.out.println(Translations.GREET_PERSON.trans(user.getName()); 
+0

Interesante uso, pero parece que podría obtener el mismo comportamiento de una serie de métodos estáticos en una clase. Supongo que no veo la ventaja de usar la enumeración. – Dave

+0

Los comentarios son mucho más fáciles de agregar cuando es necesario. También son conscientes de sí mismos: puede obtener la cadena de la enumeración dentro de trans(), por lo tanto, puede usar eso como una palabra clave para hacer coincidir en su tabla de traducciones –

8

Los tipos Enum también son una excelente manera de implementar singletons verdaderos.

Los patrones de singleton clásicos en Java normalmente implican constructores privados y métodos públicos de fábrica estáticos, pero aún son vulnerables a la creación de instancias mediante reflexión o (des) serialización. Un tipo enum protege contra eso.

+0

Aunque obtienes algún método extraño "gratis". (De todos modos los singletons son malos.) –

+0

No entiendo el comentario. –

+0

Punto de interés. ¿Cómo protege el enum contra la reflexión y la deserialización? Supongo que estoy preguntando, ¿qué es lo que realmente me impide crear una enumeración a través de la reflexión? ¿El compilador lanza una excepción marcada? – Dave

2

Dado que las instancias enum son singletons, puede usarlas en las declaraciones switch o con == para verificar la igualdad.

2

Básicamente, las enumeraciones de Java son clases (no creo que haya una diferencia en el nivel de bytecode), con la ventaja adicional de tener un conjunto fijo de posibles instancias conocidas y ser capaces de usarlas en instrucciones de conmutación .

Puede emular el "conocido conjunto fijo de instancias posibles" con clases regulares (el patrón "ensafe seguro" descrito en innumerables libros y artículos), pero es bastante trabajo (repetido para cada clase) obtenerlo funciona realmente correctamente con respecto a Serialization, equals() y hashCode(), y tal vez algunas otras cosas que olvidé. Las enumeraciones de nivel de idioma le evitan ese trabajo. Y, como se mencionó anteriormente, solo las enumeraciones de nivel de idioma se pueden usar en instrucciones de cambio.

+0

Son clases, pero hay una diferencia en el nivel de bytecode. Por un lado, las clases enum tienen el indicador ACC_ENUM. Ver http://java.sun.com/docs/books/jvms/second_edition/ClassFileFormat-Java5.pdf. –

0

Eche un vistazo a las clases de tiempo de java/joda, donde las enumeraciones hacen muchísimo trabajo.

Aquí es un ejemplo de java.time.Month:

public enum Month implements TemporalAccessor, TemporalAdjuster { 
    JANUARY, 
    FEBRUARY, 
    MARCH, 
    APRIL, 
    MAY, 
    JUNE, 
    JULY, 
    AUGUST, 
    SEPTEMBER, 
    OCTOBER, 
    NOVEMBER, 
    DECEMBER; 

    private static final Month[] ENUMS = Month.values(); 

    public static Month of(int month) { 
     if (month < 1 || month > 12) { 
      throw new DateTimeException("Invalid value for MonthOfYear: " + month); 
     } 
     return ENUMS[month - 1]; 
    } 

    // About a dozen of other useful methods go here 

}