简体   繁体   English

为什么 Java 不允许在枚举中覆盖 equals(Object)?

[英]Why Java does not allow overriding equals(Object) in an Enum?

I've noticed that the following snippet...我注意到以下代码段...

@Override
public boolean equals(Object otherObject) {
    ...
}

...is not allowed for an Enum, since the method equals(Object x) is defined as final in Enum . ...不允许用于 Enum,因为方法equals(Object x)Enum中定义为final Why is this so?为什么会这样?

I cannot think of any use case which would require overriding equals(Object) for Enum.我想不出任何需要为 Enum 覆盖equals(Object)的用例。 I'm just curious to know the reasoning behind this behavior.我只是想知道这种行为背后的原因。

Anything but return this == other would be counter intuitive and violate the principle of least astonishment . 任何东西,但return this == other将是反直觉的,并违反最不惊讶的原则 Two enum constants are expected to be equal if and only if they are the same object and the ability to override this behavior would be error prone. 当且仅当它们是同一个对象并且覆盖此行为的能力容易出错时,预期两个枚举常量是equal

Same reasoning applies to hashCode() , clone() , compareTo(Object) , name() , ordinal() , and getDeclaringClass() . 相同的推理适用于hashCode()clone()compareTo(Object)name()ordinal()getDeclaringClass()


The JLS does not motivate the choice of making it final, but mentions equals in the context of enums here . JLS并没有激励选择让它成为最终版本,但在这里的枚举语中提到了相同的内容。 Snippet: 片段:

The equals method in Enum is a final method that merely invokes super.equals on its argument and returns the result, thus performing an identity comparison. Enum的equals方法是一个最终方法, super.equals在其参数上调用super.equals并返回结果,从而执行身份比较。

There is already provides a strong intuitive notion of what it means for instances (values) of an enum to be equal. 已经提供了一个强有力的直观概念,即对enum实例(值)的意义是什么。 Allowing the overloading the equals method would lead to that notion being violated, leading to unexpected behavior, bugs and so on. 允许重载equals方法会导致违反概念,导致意外行为,错误等。

正是因为Java设计者无法想到任何可以想象的用于覆盖Enum.equals(Object)的用例,该方法被声明为final - 所以这样的覆盖是不可能的。

Sometimes we need to deal with data that does not conform to Java naming standards. 有时我们需要处理不符合Java命名标准的数据。 It would be nice to be able to do something like this: 能够做这样的事情会很高兴:

public enum Channel
{
    CallCenter("Call Center"),
    BankInternal("Bank Internal"),
    Branch("Branch");

    private final String value;

    Channel(String value)
    {
        this.value = value;
    }

    @Override
    public String toString()
    {
        return value;
    }

    public static Channel valueOf(String value)
    {
        for (Channel c : Channel.values())
            if (c.value.equals(value))
                return c;
        return null;
    }

    @Override
    public boolean equals(Object other) 
    {
        if (other instanceof String)
            other = Channel.valueOf((String)other);
        return super.equals(other);
    }
}

The "String" class would need to be modified to accommodate... 需要修改“String”类以适应......

public boolean equals (Object object) {
    if (object == this) return true;
    if (object instanceof Enum) 
        object = object.toString();
    if (object instanceof String) {
        String s = (String)object;
        // There was a time hole between first read of s.hashCode and second read
        //  if another thread does hashcode computing for incoming string object
        if (count != s.count ||
            (hashCode != 0 && s.hashCode != 0 && hashCode != s.hashCode))
                return false;
        return regionMatches(0, s, 0, count);
    }
    return false;
}

I must confess enums are the last thing I would want to override equals() in. 我必须承认枚举是我想要覆盖equals()的最后一件事。

I think the reason equals() is final in enums is that Java encourages == for enum comparison, and the implementation of equals() in enums simply uses it, So allowing equals() from being overridden is to prevent == and equals() from behaving differently, which is something other developers would not expect. 我认为equals()在枚举中是最终的原因是Java鼓励==进行枚举比较,并且枚举中equals()的实现只是使用它,因此允许重写equals()是为了防止==equals()从不同的表现,这点是其他开发商也不会想到。

I am going the majority opinion.我是大多数人的意见。 If the override of Enum::equals is forbidden, I don't think it was to follow the principle of least astonishment.如果禁止 Enum::equals 的覆盖,我不认为这是遵循最小惊讶原则。 I think it is to not break Java.我认为是不要破坏 Java。

In the JVM, and in some old classes such like EnumMap, Enum identities may be coded internally with an int.在 JVM 和一些旧类(如 EnumMap)中,Enum 标识可能在内部使用 int 进行编码。 For example, if we allow to override Enum::equals, then EnumMap<K, V> would break the contract of Map.例如,如果我们允许覆盖 Enum::equals,那么 EnumMap<K, V> 将违反 Map 的约定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM