Definición de enumeración de Java

Resuelto Dónal asked hace 15 años • 7 respuestas

Pensé que entendía bastante bien los genéricos de Java, pero luego encontré lo siguiente en java.lang.Enum:

class Enum<E extends Enum<E>>

¿Alguien podría explicar cómo interpretar este parámetro de tipo? Puntos de bonificación por proporcionar otros ejemplos de dónde se podría utilizar un parámetro de tipo similar.

Dónal avatar Oct 17 '08 12:10 Dónal
Aceptado

Significa que el argumento de tipo para enum tiene que derivar de una enumeración que a su vez tiene el mismo argumento de tipo. ¿Cómo puede suceder esto? Haciendo que el argumento de tipo sea el nuevo tipo en sí. Entonces, si tengo una enumeración llamada StatusCode, sería equivalente a:

public class StatusCode extends Enum<StatusCode>

Ahora, si verificas las restricciones, tenemos Enum<StatusCode>- entonces E=StatusCode. Comprobemos: ¿se Eextiende Enum<StatusCode>? ¡Sí! Estamos bien.

Quizás te preguntes cuál es el objetivo de esto :) Bueno, significa que la API para Enum puede referirse a sí misma; por ejemplo, puede decir que Enum<E>implementa Comparable<E>. La clase base puede hacer comparaciones (en el caso de enumeraciones), pero puede asegurarse de que solo compara el tipo correcto de enumeraciones entre sí. (EDITAR: Bueno, casi; vea la edición en la parte inferior).

He usado algo similar en mi puerto C# de ProtocolBuffers. Hay "mensajes" (inmutables) y "constructores" (mutables, utilizados para crear un mensaje), y vienen en pares de tipos. Las interfaces involucradas son:

public interface IBuilder<TMessage, TBuilder>
  where TMessage : IMessage<TMessage, TBuilder> 
  where TBuilder : IBuilder<TMessage, TBuilder>

public interface IMessage<TMessage, TBuilder>
  where TMessage : IMessage<TMessage, TBuilder> 
  where TBuilder : IBuilder<TMessage, TBuilder>

Esto significa que de un mensaje puede obtener un constructor apropiado (por ejemplo, para tomar una copia de un mensaje y cambiar algunos bits) y de un constructor puede obtener un mensaje apropiado cuando haya terminado de construirlo. Es un buen trabajo, los usuarios de la API no necesitan preocuparse por esto: es tremendamente complicado y requirió varias iteraciones para llegar a donde está.

EDITAR: Tenga en cuenta que esto no le impide crear tipos impares que utilicen un argumento de tipo que en sí mismo está bien, pero que no es del mismo tipo. El propósito es brindar beneficios en el caso correcto en lugar de protegerlo del caso equivocado .

Entonces, si Enumde todos modos no se manejara "especialmente" en Java, podría (como se indica en los comentarios) crear los siguientes tipos:

public class First extends Enum<First> {}
public class Second extends Enum<First> {}

Secondimplementaría Comparable<First>en lugar de Comparable<Second>... pero Firsten sí mismo estaría bien.

Jon Skeet avatar Oct 17 '2008 05:10 Jon Skeet

La siguiente es una versión modificada de la explicación del libro Java Generics and Collections : Tenemos una Enumdeclaración

enum Season { WINTER, SPRING, SUMMER, FALL }

que se ampliará a una clase

final class Season extends ...

donde ...será la clase base parametrizada de alguna manera para Enums. Averigüemos qué tiene que ser eso. Bueno, uno de los requisitos Seasones que se debe implementar Comparable<Season>. Entonces vamos a necesitar

Season extends ... implements Comparable<Season>

¿Qué podrías usar para ...que esto permita que esto funcione? Dado que tiene que ser una parametrización de Enum, la única opción es Enum<Season>, para que puedas tener:

Season extends Enum<Season>
Enum<Season> implements Comparable<Season>

También Enumestá parametrizado en tipos como Season. Resuma de Seasony obtendrá que el parámetro de Enumes cualquier tipo que satisfaga

 E extends Enum<E>

Maurice Naftalin (coautor, Colecciones y genéricos de Java)

Maurice Naftalin avatar Apr 17 '2009 00:04 Maurice Naftalin

Esto se puede ilustrar con un ejemplo sencillo y una técnica que se puede utilizar para implementar llamadas a métodos encadenados para subclases. En el siguiente ejemplo, setNamese devuelve un Nodevalor por lo que el encadenamiento no funcionará para City:

class Node {
    String name;

    Node setName(String name) {
        this.name = name;
        return this;
    }
}

class City extends Node {
    int square;

    City setSquare(int square) {
        this.square = square;
        return this;
    }
}

public static void main(String[] args) {
    City city = new City()
        .setName("LA")
        .setSquare(100);    // won't compile, setName() returns Node
}

Entonces podríamos hacer referencia a una subclase en una declaración genérica, de modo que Cityahora devuelva el tipo correcto:

abstract class Node<SELF extends Node<SELF>>{
    String name;

    SELF setName(String name) {
        this.name = name;
        return self();
    }

    protected abstract SELF self();
}

class City extends Node<City> {
    int square;

    City setSquare(int square) {
        this.square = square;
        return self();
    }

    @Override
    protected City self() {
        return this;
    }

    public static void main(String[] args) {
       City city = new City()
            .setName("LA")
            .setSquare(100);                 // ok!
    }
}
Andrey Chaschev avatar Nov 27 '2013 22:11 Andrey Chaschev

No eres el único que se pregunta qué significa eso; consulte el blog Caótico de Java .

"Si una clase extiende esta clase, debe pasar un parámetro E. Los límites del parámetro E son para una clase que extiende esta clase con el mismo parámetro E".

kpirkkal avatar Oct 17 '2008 05:10 kpirkkal