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

use*_*413 58 java enums enumeration

我试图理解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;
    }
}
Run Code Online (Sandbox Code Playgroud)

上面和下面的代码有什么区别?

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

nne*_*neo 59

区别:

  1. 枚举扩展java.lang.Enum并获得其所有优秀功能:
    1. 通过正确的序列化自动单例行为
    2. .toString枚举值的自动人类可读方法,无需复制枚举名称
    3. .name.ordinal特殊用途的方法
    4. 可用于基于高性能bitset EnumSetEnumMap
  2. 枚举用特殊语言处理:
    1. 枚举使用特殊语法,简化了实例创建,无需编写数十个public static final字段
    2. 枚举可用于switch陈述中
    3. 除非使用反射,否则无法在枚举列表外实例化枚举
    4. 枚举不能扩展到枚举列表之外
  3. Java自动将额外的东西编译到枚举中:
    1. public static (Enum)[] values();
    2. public static (Enum) valueOf(java.lang.String);
    3. private static final (Enum)[] $VALUES;(values()返回此的克隆)

其中大部分都可以使用适当设计的类进行模拟,但Enum只是使用这组特别理想的属性创建类非常容易.


Psy*_*nch 10

回答这个问题:基本上,这两种方法没有区别.但是,enum构造为您提供了一些额外的支持方法,例如values(),valueOf()等等,您必须使用class-with-private-constructor方法自行编写.

但是,我喜欢Java枚举大多与Java中的任何其他类一样,它们可以有字段,行为等.但是对于我来说,将枚举与普通类分开的是枚举是其实例/成员的类/类型的想法是预定的.与可以从中创建任意数量实例的常规类不同,枚举仅限于创建已知实例.是的,正如您所说明的,您也可以使用私有构造函数的类来执行此操作,但枚举只是使这更直观.


mth*_*ers 7

看一下这个博客页面,它描述了如何将Java enum编译成字节码.与第二个代码示例相比,您会看到有一个小的添加,这是一个Direction被称为对象的数组VALUES.此数组包含枚举的所有可能值,因此您将无法执行此操作

new Direction(2, 2)
Run Code Online (Sandbox Code Playgroud)

(例如使用反射)然后将其用作有效值Direction.

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


Bor*_*der 5

正如人们指出你输了values(),valueOf()而且ordinal().您可以使用a Map和a 的组合相当轻松地复制此行为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;
    }
}
Run Code Online (Sandbox Code Playgroud)

如你看到的; 代码变得非常笨重很快.

我不确定是否有办法复制switch这个类的语句; 所以你会失去那个.