¿Por qué no puedo recurrir en una definición de tipo genérico java java.lang.Enum?

CorePress2024-01-25  13

Esta es una pregunta académica destinada a comprender mejor el comportamiento de los genéricos en este escenario.

El tipo Enum se describe como "la clase base común de todos los tipos de enumeración del lenguaje Java". Su definición es:

public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable {

} 

Ahora, podría definir un campo con esta definición:

public class MyClass { 
   public Enum<MyEnum> field;
}

Todo bien. Ahora, da un paso más. Desde Enum<MyEnum> es aparentemente equivalente a MyEnum lo que me haría creer que según la definición también podría escribir:

public class MyClass { 
   public Enum<Enum<MyEnum>> field;
}

Pero ahora el compilador realmente me detiene: el parámetro de tipo 'java.lang.Enum' no está dentro de su límite; debería extender 'java.lang.Enum<MyEnum>> lo cual hace de acuerdo con la definición ya que todavía satisface: E extiende Enum<E>. Por supuesto, hay todo tipo de reaHijos, por qué no permitirían una construcción tan recurrente (o quizás mejor, incurrida), pero la dada me parece incorrecta.

Por otro lado, si tuviera que definir una clase como esta (en forma análoga a la definición de Enum)

public class Wrapper<T extends Number> { 
} 

Podría escribir una clase:

public class MyClass { 
   // satisfies the upper bound
   public Wrapper<Integer> field1;

   // also satisfies the upper bound
   public Wrapper<Number> field2;
}

¿Estoy pasando por alto algo o mi análisis está equivocado?

5

Perdón si no entiendo bien el problema, pero ¿puede funcionar el campo público MyEnum?

- Kaj Hejer

28/03/2021 a las 10:07

1

"Podría definir un campo con esta definición: public Enum<MyEnum> campo" --- ¿Por que lo harias? ¿Por qué no definirlo simplemente como campo público MyEnum, ya que MyEnum extiende Enum<MyEnum> y será la única clase que lo hará?

- Andreas

28/03/2021 a las 10:16

1

No se trata de soluciones prácticas. Es para entender mejor el idioma.

- Sjaak

28/03/2021 a las 11:06



------------------------------------

Supongo que se trata de una cuestión académica. En realidad, no estás escribiendo un código como este, solo quieres entender mejor el lenguaje, ¿verdad? Porque en código real, por supuesto, simplemente escribirías:

public MyEnum myField;

Con ese espíritu—

Desde Enum<MyEnum> es aparentemente equivalente a MyEnum...

No son equivalentes. MyEnum es una subclase de Enum<MyEnum>. La clase autogenerada es algo como:

public final class MyEnum extends Enum<MyEnum> {
    ...
}

Eso significa que no puedes seguir expandiendo la disminución.aración con Enum<Enum<MyEnum>>. Podrías escribir esto, si así lo deseas:

public Enum<? extends Enum<MyEnum>> field;

Eso se compilaría y las posibilidades recursivas terminarían ahí.

Lo que entiendo de un límite superior X en T extiende X e incluye X y sus subclases. Entonces Enum<Enum> debería estar permitido pero no lo está.

Echemos un vistazo a qué es exactamente E, la E de aquí:

public abstract class Enum<E extends Enum<E>>

Cuando escribes Enum<Enum<MyEnum>>, E es Enum<MyEnum>. ¿Esta E coincide con la restricción E extiende Enum<E>? Necesitamos sustituir E por Enum<MyEnum>.

E extends Enum<E>?
^              ^

Enum<MyEnum> extends Enum<Enum<MyEnum>>?
^^^^^^^^^^^^              ^^^^^^^^^^^^

Ahora respondamos un par de preguntas relacionadas pero sutilmente diferentes:

¿MyEnum extiende Enum<MyEnum>? Sí. El código generado automáticamente que mencioné anteriormente muestra que este es el caso.

¿Enum<MyEnum?> ¿Extender Enum<MyEnum>? Sí. Como describe correctamente en su ejemplo de Número, una clase se considera una subclase de sí misma en lo que respecta a la palabra clave extends.

Y ahora la pregunta que nos preocupa aquí y ahora: ¿Enum<MyEnum> extender Enum<Enum<MyEnum>>? No, no es así. Esta es la relación que debería mantenerse para que el código que intentaste funcione. No se mantiene y es por eso que su código no se compila.

4

Sí... es académico. Y no... ciertamente lo haré.No podría escribir código como este :). Pero estoy involucrado en la construcción de un procesador de anotaciones que requiere tipos coincidentes. Y deberíamos poder cubrir todos los escenarios. Por eso me gustaría entender por qué mi razonamiento sale mal. Necesito pensar más en tu respuesta. Supongamos una clase: public class Wrapper<T extends Number> {} . Podría crear un campo como este: public class MyType{ public Wrapper<Number> campo; } ¿bien? El límite superior también incluye Número sin recurrir a comodines.

- Sjaak

28/03/2021 a las 10:42

Amplié mi ejemplo, solo para dejar claro que es una cuestión académica. Entiendo que MyEnumis una subclase de Enum<MyEnum> pero eso todavía satisface el límite superior, ¿verdad? Es inclusivo (de ahí mi ejemplo con Número).

- Sjaak

28/03/2021 a las 11:01

Entonces lo que quise decir, el argumento de: Enum<Enum<MyEnum>> es Enum<MyEnum> o Enum sin formato. Lo que entiendo de un límite superior X en T extiende X e incluye X y sus subclases. Entonces Enum<Enum> debería permitirseed pero no lo es. Y es aquí donde no entiendo en qué se diferencia de mi ejemplo de Número.

- Sjaak

28/03/2021 a las 15:05

Tu respuesta es perfectamente clara y realmente me ayudó mucho. Muchas gracias por el tiempo invertido. Aunque para mí el momento ajá llegó con la respuesta de @Andreas arriba. La parte que confundió fue la extensión encuadernada. Después de todo, Enum (sin procesar) está dentro de los límites de E extiende Enum. Pero es el parámetro de tipo genérico X Enum<X> eso lo estropea.

- Sjaak

29 de marzo de 2021 a las 6:36



------------------------------------

Con Enum<Enum<MyEnum>>, hace que E sea igual a Enum<MyEnum>.

La E enlazada extiende Enum<E> por lo tanto requiere que Enum<MyEnum> debe extender Enum<Enum<MyEnum>>, lo cual no es así y, por lo tanto, el compilador lo rechaza.

Recuerde, Enum es la superclase implícita de una enumeración.

Cuando escribes enum MyEnum { ... }, lo que obtienes en realidad es class MyEnum extends Enum<MyEnum> {...}.

Lo que hace que E sea igual a MyEnum.

La E enlazada extiende Enum<E> por lo tanto requiere que MyEnum extienda Enum<MyEnum>, lo cual hace, por lo que el compilador está contento.

2

Me tomó algo de ayuda darme cuenta de esto. Lo que estás diciendo en una relación T extiende SomeType<A>, T nunca puede ser igual a SomeType<B>. Tiene que ser: SomeType<A> u OtroTipo<A> donde OtroTipo<T> es una clase definida como la clase pública AnotherType<T> extiende SomeType<T>{...}

- Sjaak

28/03/2021 a las 19:10

@Sjaak Correcto, y eso se debe a esto: Is List<Dog> ¿una subclase de Lista<Animal>? ¿Por qué los genéricos de Java no son implícitamente polimórficos?

- Andreas

29 de marzo de 2021 a las 1:31

randomThread
Tengo Python 2.7 y 3.8 en mi sistema, ¿cómo puedo usar Python 3.8 o eliminar 2.7?Python - Pandas: cómo seleccionar filas según múltiples criterios (si no es nan y es igual a un valor específico)python - discordia,>, no compatible entre instancias de, Context y, int,java - MainActivity con inyección de dependenciaMatriz de números mecanografiados sin errores si está vacíaoop: inicializa una matriz aleatoria con un número fijo de variables en Javavb.net: convierte la fecha Hijri como cadena en un objeto DateTimePython - ¿Cómo reemplazar el primer carácter de todas las claves en un diccionario?html: quiero agregar un efecto de desplazamientojavascript - ¿Cómo llamar a un php con parámetro de un