我试图理解Java枚举是如何工作的,我得出的结论是它与普通的Java类非常相似,它的构造函数被声明为私有。
我刚刚得出这个结论,并不是基于多少思考,但我想知道我是否遗漏了任何东西。
下面是一个简单的Java枚举和一个等效的Java类的实现。
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;
}
}
上面和下面的代码之间有什么区别?
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;
}
}
答案 0 :(得分:57)
的差异:
java.lang.Enum
并获得所有nice features:
.toString
方法,无需复制枚举名称.name
和.ordinal
专用方法EnumSet
和EnumMap
类public static final
字段switch
语句public static (Enum)[] values();
public static (Enum) valueOf(java.lang.String);
private static final (Enum)[] $VALUES;
(values()
返回此克隆)大多数这些都可以使用适当设计的类进行模拟,但Enum
只是使用这组特别理想的属性创建一个类非常容易。
答案 1 :(得分:9)
回答这个问题:基本上,这两种方法没有区别。但是,enum构造为您提供了一些其他支持方法,如values()
,valueOf()
等,您必须使用class-with-private-constructor方法自行编写。
但是,我喜欢Java枚举大多与Java中的任何其他类一样,它们可以有字段,行为等。但是对于我来说,将枚举与普通类分开的是枚举是类/类型的想法实例/成员是预先确定的。与可以从中创建任意数量实例的常规类不同,枚举仅限于创建已知实例。是的,正如您所说明的那样,您也可以使用私有构造函数的类来执行此操作,但枚举只是使这更直观。
答案 2 :(得分:6)
看一下this blogpage,它描述了如何将Java enum
编译成字节码。与第二个代码示例相比,您会看到一个小的添加,这是一个名为Direction
的{{1}}个对象数组。此数组包含枚举的所有可能值,因此您将无法执行
VALUES
(例如使用反射),然后将其用作有效的new Direction(2, 2)
值。
另外,正如@Eng.Fouad正确解释的那样,您没有Direction
,values()
和valueOf()
。
答案 3 :(得分:5)
正如人们指出的那样,你失去了values()
,valueOf()
和ordinal()
。您可以使用Map
和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;
}
}
正如你所看到的;代码变得非常笨重。
我不确定是否有办法用这个类复制switch
语句;所以你会失去它。
答案 4 :(得分:0)
主要区别在于每个enum
类隐式扩展Enum<E extends Enum<E>>
类。这导致:
enum
个对象包含name()
和ordinal()
enum
个对象具有特殊toString()
,hashCode()
,equals()
和compareTo()
实施enum
个对象适合switch
运算符。上述所有内容均不适用于您的Direction
课程版本。这是“意义”的区别。