reales - ¿Cuáles son las diferencias entre una enumeración de Java y una clase con un constructor privado?
libro de android studio en español pdf (5)
Como las personas han señalado, pierdes values()
, valueOf()
y ordinal()
. Puede replicar este comportamiento con bastante facilidad utilizando una combinación de un Map
y una List
.
public class Direction {
public static final Direction UP = build("UP", 0, -1);
public static final Direction DOWN = build("DOWN", 0, 1);
public static final Direction LEFT = build("LEFT", -1, 0);
public static final Direction RIGHT = build("RIGHT", 1, 0);
private static final Map<String, Direction> VALUES_MAP = new LinkedHashMap<>();
private static final List<Direction> VALUES_LIST = new ArrayList<>();
private final int x;
private final int y;
private final String name;
public Direction(int x, int y, String name) {
this.x = x;
this.y = y;
this.name = name;
}
private static Direction build(final String name, final int x, final int y) {
final Direction direction = new Direction(x, y, name);
VALUES_MAP.put(name, direction);
VALUES_LIST.add(direction);
return direction;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public static Direction[] values() {
return VALUES_LIST.toArray(new Direction[VALUES_LIST.size()]);
}
public static Direction valueOf(final String direction) {
if (direction == null) {
throw new NullPointerException();
}
final Direction dir = VALUES_MAP.get(direction);
if (dir == null) {
throw new IllegalArgumentException();
}
return dir;
}
public int ordinal() {
return VALUES_LIST.indexOf(this);
}
@Override
public int hashCode() {
int hash = 7;
hash = 29 * hash + name.hashCode();
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Direction other = (Direction) obj;
return name.equals(other.name);
}
@Override
public String toString() {
return name;
}
}
Como puedes ver; El código se vuelve muy torpe muy rápidamente.
No estoy seguro de si hay una manera de replicar una instrucción switch
con esta clase; así que perderás eso.
Esta pregunta ya tiene una respuesta aquí:
Estaba tratando de entender cómo funciona realmente la enumeración de Java y he llegado a la conclusión de que es muy similar a una clase de Java normal que tiene su constructor declarado privado.
Acabo de llegar a esta conclusión y no se basa en pensar mucho, pero me gustaría saber si me olvido de algo.
A continuación se muestra una implementación de una enumeración simple de Java y una clase de Java equivalente.
public enum Direction {
ENUM_UP(0, -1),
ENUM_DOWN(0, 1),
ENUM_RIGHT(1, 0),
ENUM_LEFT(-1, 0);
private int x;
private int y;
private Direction(int x, int y){
this.x = x;
this.y = y;
}
public int getEnumX(){
return x;
}
public int getEnumY(){
return y;
}
}
¿Cuál es la diferencia de significado entre el código de arriba y el de abajo?
public class Direction{
public static final Direction UP = new Direction(0, -1) ;
public static final Direction DOWN = new Direction(0, 1) ;
public static final Direction LEFT = new Direction(-1, 0) ;
public static final Direction RIGHT = new Direction(1, 0) ;
private int x ;
private int y ;
private Direction(int x, int y){
this.x = x ;
this.y = y ;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
}
Diferencias
- Enums extiende
java.lang.Enum
y gana todas sus características agradables :- Comportamiento singleton automático a través de la serialización correcta.
- Método
.toString
automático legible por.toString
en los valores de enumeración sin la necesidad de duplicar sus nombres de enumeración -
.ordinal
de propósito especial.name
y.ordinal
-
EnumMap
clasesEnumSet
yEnumMap
basadas enEnumSet
alto rendimiento
- Enums son tratados por el idioma especialmente:
- Las enumeraciones utilizan una sintaxis especial que simplifica la creación de instancias sin escribir docenas de campos
public static final
- Enums se pueden utilizar en declaraciones de
switch
- Enums no se pueden crear instancias fuera de la lista de enumeración, excepto mediante el uso de la reflexión
- Las enumeraciones no se pueden extender fuera de la lista de enumeración
- Las enumeraciones utilizan una sintaxis especial que simplifica la creación de instancias sin escribir docenas de campos
- Java compila automáticamente cosas extra en enumeraciones:
-
public static (Enum)[] values();
-
public static (Enum) valueOf(java.lang.String);
-
private static final (Enum)[] $VALUES;
(values()
devuelve un clon de esto)
-
La mayoría de estos se pueden emular con una clase diseñada adecuadamente, pero Enum
solo hace que sea realmente fácil crear una clase con este conjunto de propiedades particularmente deseables.
Eche un vistazo a esta página de blog , describe cómo se compilan las enumas de Java en el bytecode. Verá que hay una pequeña adición en comparación con su segundo ejemplo de código, que es una matriz de objetos de Direction
llamados VALUES
. Esta matriz contiene todos los valores posibles para su enumeración, por lo que no podrá hacer
new Direction(2, 2)
(por ejemplo, utilizando la reflexión) y luego usarlo como un valor de Direction
válido.
Además, como @ Eng.Fouad explica correctamente, no tiene values()
, valueOf()
y ordinal()
.
La principal diferencia es que cada clase de enum
extiende implícitamente la clase Enum<E extends Enum<E>>
clase Enum<E extends Enum<E>>
. Esto lleva a eso:
-
enum
objetos deenum
tienen métodos comoname()
yordinal()
-
enum
objetosenum
tienen implementaciones especiales paratoString()
,hashCode()
,equals()
ycompareTo()
- objetos
enum
son adecuados para el operador delswitch
.
Todo lo mencionado anteriormente no es aplicable para su versión de clase de Direction
. Esta es la diferencia de "significado".
Para responder a la pregunta: esencialmente, no hay diferencia entre los dos enfoques. Sin embargo, la construcción de enumeración le proporciona algunos métodos de soporte adicionales como los values()
, valueOf()
, etc., que tendría que escribir por su cuenta con el enfoque de clase con constructor privado.
Pero sí, me gusta cómo las enumeraciones de Java son casi como cualquier otra clase en Java, pueden tener campos, comportamientos, etc. Pero para mí lo que separa las enumeraciones de las clases simples es la idea de que las enumeraciones son clases / tipos cuyas instancias / miembros Están predeterminados. A diferencia de las clases habituales en las que puede crear cualquier número de instancias, las enumeraciones solo limitan la creación a instancias conocidas. Sí, como ha ilustrado, también puede hacer esto con clases con constructores privados, pero las enumeraciones simplemente lo hacen más intuitivo.