2010-06-18 12 views
12

Por favor, vea Java Enum definition y Why in java enum is declared as Enum<E extends Enum<E>> para una discusión general. Aquí me gustaría saber cuál sería rota (no Typesafe más, o que requieren moldes adicionales, etc.) si la clase Enum se definió como¿Qué sería diferente en Java si la declaración Enum no tenía la parte recursiva

public class Enum<E extends Enum> 

Estoy usando este código para probar mis ideas:

interface MyComparable<T> { 
    int myCompare(T o); 
} 

class MyEnum<E extends MyEnum> implements MyComparable<E> { 
    public int myCompare(E o) { return -1; } 
} 

class FirstEnum extends MyEnum<FirstEnum> {} 

class SecondEnum extends MyEnum<SecondEnum> {} 

Con él no pude encontrar ningún beneficio en este caso exacto.

PS. el hecho de que no se me permite hacer

class ThirdEnum extends MyEnum<SecondEnum> {} 

cuando MyEnum se define con la recursividad es
a) no es relevante, ya que con enumeraciones reales no se le permite hacer eso sólo porque no se puede extender enumeración usted mismo
b) no es verdad - pls intentarlo en un compilador y ver que de hecho es capaz de compilar sin errores

PPS. Cada vez me inclino más a creer que la respuesta correcta sería "nada cambiaría si eliminas la parte recursiva", pero no puedo creerlo.

Respuesta

1

Creo que una razón de peso para hacerlo es que hace que el código en la clase MyEnum sea más seguro.

consideran que la parte recursiva hace posible tal cosa:

class MyEnum<E extends MyEnum<E>> { 
    private Thing<E> util1() { return someObject } 
    private void util2(E e) {} 
    public int method(E o) { 
     Thing<E> thingy = o.util1(); 
     // You can call the util1 method on o and get a type safe return element. 
     E o1 = // I don't care how you get a parametrized E object. 
     o.util2(o1); 
     // You can call the util2 method with a typesafe parameter. 
    } 
} 

En resumen, que la recursividad le permite poner métodos typesafe en la clase de enumeración que puede llamar en cualquier elemento E, y estas llamadas se tipo seguro.

+1

sólo una pequeña nota, 'o.util2 (este)' no compilar ya que se considera MyEnum no E. Se podría añadir un segundo parámetro 'o1' E y llamar' o.util2 (o1) 'si fuera la misma efecto: se compilará con 'E se extiende MyEnum ', pero no con' E se extiende MyEnum ' –

+0

Gracias, acabo corregido ese error. –

+0

¡gracias! ¡ese código de hecho está marcado como inseguro si elimina la recursión! ¿Conoces algún uso real de esa función en jdk? – atamur

1

Considera Enum<E>.compareTo(E other).

Que:

  • necesita trabajar con E en lugar de enumeración de manera que usted no intenta comparar un valor de enumeración con un valor de una enumeración diferente
  • necesita ser capaz de obtener el ordinal valor de la enumeración, a través del método ordinal()declarado en Enum.

¿Cómo propones hacer ese trabajo sin la restricción actual?

Esa es solo la primera que se me ocurrió ... Estoy seguro de que hay muchas otras. Básicamente es una forma de decir: "No intente tratar todas las enumeraciones como equivalentes entre sí ... una enumeración es un conjunto cerrado en sí mismo, pero todas las enums comparten ciertas propiedades".

+0

compararTo - ver mi qn. De esa manera, funciona exactamente como dices. Sin ninguna recursión. Tampoco ve un problema con el ordinal: ¿podría proporcionar algún código que se rompa/no sea seguro? – atamur

+0

@atamur: No había notado el bit de tipo raw en tu ejemplo (¿lo editaste dentro de los primeros cinco minutos de preguntar? Tal vez lo he leído mal). El hecho de que necesites un tipo sin procesar inmediato me pone nervioso, para ser honesto ... –

+0

Si el ordinal es el motivo, entonces 'clase Enum >' sería suficiente. – newacct

2

Bueno, primero de todo es que se queja de utilizar el tipo de crudo, pero que podría ser:

public class Enum<E extends Enum<?>> 

para el mismo efecto.

Además, con este tipo de genérico que podría hacer algo como:

class FirstEnum extends MyEnum<SecondEnum> { 
} 

class SecondEnum extends MyEnum<FirstEnum> { 
} 

la que me parece que podría dar lugar a un montón de problemas. Más exactamente, no puede comparar una enumeración de tipo FirstEnum con una enumeración del mismo tipo, tiene que compararla con una enumeración del otro tipo, lo cual es realmente problemático si tiene un List<FirstEnum> que desea ordenar.El ejemplo no se compilará si configuro E en su lugar o ? ya que SecondEnum no es del tipo E extends MyEnum<E> (esto daría lugar a una herencia circular). Sin embargo, funcionará si FirstEnum extends MyEnum<FirstEnum> (lo que significa que SecondEnum es una clase hija de FirstEnum - herencia jerárquica normal).

+0

El tipo sin formato suena interesante, pero javac no emite ninguna advertencia en bruto si realmente lo intentas. pls ver mi ps en el qn. Hay 2 puntos por los cuales esto no es relevante. – atamur

+1

Estoy usando eclipse y me da una advertencia sobre el tipo sin procesar (sin mencionar que sun ha dicho que ya no deberíamos usar tipos crudos). Tal vez javac requiere algún tipo de opción activada para quejarse de esto? –

+1

Además, el segundo punto de la ps no es cierto para mi ejemplo, si configuro la clase 'public class MyEnum >' no se compila. En cuanto al primer punto, creo que podría generar el archivo .class para que tenga las firmas de métodos como las clases se escribieron así (mediante el uso de un compilador no estándar) aunque javac no le permitió compilar ' public enum FirstEnum extiende MyEnum 'o algo similar. –

0

Si no tiene el parámetro de tipo genérico, no podrá ampliar Comparable<T extends Comparable> para el subtipo específico de enumeración que ha creado.

Se podía ignorar esto, y crear su propio tipo MyEnum que se comporta de la misma, pero sin la restricción de que diferentes MyEnum no son comparables:

public abstract class MyEnum implements Comparable<MyEnum> 
{ 
    private final int ordinal; 

    protected MyEnum (int ordinal) 
    { 
     this.ordinal = ordinal; 
    } 

    public int ordinal() 
    { 
     return ordinal ; 
    } 

    public int compareTo (MyEnum other) 
    { 
     return ordinal - other.ordinal; // ignore overflow for now 
    } 

    public boolean equals (Object other) { 
     return ordinal == ((MyEnum)other).ordinal; 
    } 

    public int hashCode() { 
     return ordinal; 
    } 
} 

Esto se comporta de la misma manera que una enumeración haría para las operaciones definidas, pero en lugar de ser una implementación segura de tipo genérico obedece a LSP - los objetos de diferentes subclases de MyEnum son comparables o iguales entre sí si tienen el mismo valor ordinal.

public static class EnumA extends MyEnum 
{ 
    private EnumA (int ordinal) { super (ordinal); } 
    public static final EnumA a = new EnumA (0); 
    public static final EnumA b = new EnumA (1); 
} 

public static class EnumB extends MyEnum 
{ 
    private EnumB (int ordinal) { super (ordinal); } 
    public static final EnumB x = new EnumB (0); 
    public static final EnumB y = new EnumB (1); 
} 

public static void main (String...args) 
{ 
    System.out.println (EnumA.a.compareTo (EnumB.x)); 
    System.out.println (EnumA.a.equals (EnumB.x)); 
    System.out.println (EnumA.a.compareTo (EnumB.y)); 
    System.out.println (EnumA.a.equals (EnumB.y)); 
} 

En este caso, si no se sobreescribe equals, se pierde la convención que implica x.comparesTo(y)=0x.equals(y); si anula Igual, entonces hay casos en que x.equals(y) no implica x == y (como para otros objetos de valor), mientras que para las enumeraciones Java ambas pruebas de igualdad producen el mismo resultado.

+0

Me temo que no entendiste mi qn. Si miras mi código, MyEnum está usando genéricos, simplemente no es el bit recursivo. – atamur

0
`X extends Enum<Y>` 

sería ilegal. que es relavant. el compilador puede tener reglas especiales con enum, pero ¿por qué no tener una declaración de tipo perfecto si es posible?

Cuestiones relacionadas