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

问题描述 投票:55回答:5

我试图理解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;
    }
}
java enums enumeration
5个回答
57
投票

区别:

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

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


9
投票

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

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


6
投票

看看this blogpage,它描述了如何将Java enums编译成字节码。你会看到与你的第二个代码示例相比有一个小的增加,这是一个名为DirectionVALUES对象数组。此数组包含枚举的所有可能值,因此您将无法执行此操作

new Direction(2, 2)

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

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


5
投票

正如人们指出你失去了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语句;所以你会失去那个。


0
投票

主要的区别是每个enum类隐含地扩展了Enum<E extends Enum<E>>类。这导致:

  1. enum对象有name()ordinal()等方法
  2. enum对象有特殊的toString()hashCode()equals()compareTo()实现
  3. enum对象适用于switch运算符。

上述所有内容均不适用于您的Direction类。这是“意义”的区别。

© www.soinside.com 2019 - 2024. All rights reserved.