Java枚举和带有私有构造函数的类之间有什么区别?

我试图理解Java枚举是如何工作的,而且我得出的结论与一般的Java类非常类似,它的构造函数声明为private。

我刚刚得出这个结论,并不是基于很多的想法,但我想知道我是否错过任何东西。

所以下面是一个简单的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; } } 

区别:

  1. 枚举扩展java.lang.Enum并获得其所有好的function :
    1. 通过正确的序列化自动单例行为
    2. 在枚举值上自动生成可读的.toString方法,而不需要复制枚举名
    3. .name.ordinal特殊用途的方法
    4. 可用于高性能的基于位集的EnumSetEnumMap
  2. 枚举被特定的语言处理:
    1. 枚举使用特殊的语法来简化实例创build,而不用编写数十个public static final字段
    2. 枚举可以用在switch语句中
    3. 枚举不能在枚举列表之外实例化,除了使用reflection
    4. 枚举不能在枚举列表之外扩展
  3. Java自动编译额外的东西到枚举中:
    1. public static (Enum)[] values();
    2. public static (Enum) valueOf(java.lang.String);
    3. private static final (Enum)[] $VALUES;values()返回这个的一个副本)

其中大部分可以用适当devise的类来模拟,但Enum只是使用这组特别需要的属性创build一个类非常容易。

看看这个博客页面 ,它描述了如何将Java enum编译成字节码。 您将看到,与您的第二个代码示例(这是一个名为VALUESDirection对象数组)相比,它有一个小的增加。 这个数组包含了你的枚举的所有可能的值,所以你将无法做到

 new Direction(2, 2) 

(例如使用reflection),然后将其用作有效的Direction值。

另外,正如@ Eng.Fouad正确解释的,你没有values()valueOf()ordinal()

为了回答这个问题:实质上,这两种方法没有区别。 但是,enum构造提供了一些额外的支持方法,比如values()valueOf()等等,你必须用class-private-constructor方法自己编写。

但是,我喜欢Java枚举类似于Java中的其他任何类,他们可以有字段,行为等等。但是对于枚举类和普通类的区别在于枚举类是其实例/成员是预定的。 与通常可以创build任意数量实例的类不同,枚举只能将创build限制为已知实例。 是的,正如你所说的,你也可以使用私有构造函数来完成这个工作,但枚举只是让这个更直观。

正如人们指出的,你失去了values()valueOf()ordinal() 。 您可以使用MapList的组合相当容易地复制此行为。

 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语句; 所以你会失去的。

主要区别在于每个enum类都隐式扩展了Enum<E extends Enum<E>>类。 这导致:

  1. enum对象具有name()ordinal()
  2. enum对象具有特殊的toString()hashCode()equals()compareTo()实现
  3. enum对象适合switch操作员。

上面提到的所有内容都不适用于您的Direction类的版本。 这是“意义”的区别。