【问题标题】:Why Java does not allow overriding equals(Object) in an Enum?为什么 Java 不允许在枚举中覆盖 equals(Object)?
【发布时间】:2011-02-27 05:26:38
【问题描述】:

我注意到下面的 sn-p...

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

...不允许用于枚举,因为方法 equals(Object x)Enum 中定义为 final。为什么会这样?

我想不出任何需要为 Enum 覆盖 equals(Object) 的用例。我只是想知道这种行为背后的原因。

【问题讨论】:

  • 我的用例是当我通过 JSON 接收字符串值并想查看它是否与我的枚举中的现有值匹配时。虽然在我的情况下,我有一个枚举构造函数,它接收一个字符串值,我将它保存在一个私有变量中,所以在一天结束时我会比较我猜的字符串。但我更喜欢MY_ENUM.VALUE.equals("hello") 然后MY_ENUM.VALUE.toString().equals("hello") 希望这是有道理的。

标签: java enums api-design


【解决方案1】:

return this == other 之外的任何内容都会违反直觉并违反the principle of least astonishment。当且仅当它们是同一个对象并且覆盖此行为的能力容易出错时,两个枚举常量应为equal

同样的推理适用于hashCode()clone()compareTo(Object)name()ordinal()getDeclaringClass()


JLS 不会促使选择将其定为 final,但在枚举 here 的上下文中提到 equals。片段:

Enum 中的 equals 方法是最终方法,它仅在其参数上调用 super.equals 并返回结果,从而执行身份比较。

【讨论】:

    【解决方案2】:

    对于 enum 的实例(值)相等意味着什么,已经提供了一个非常直观的概念。允许重载 equals 方法会导致违反该概念,导致意外行为、错误等。

    【讨论】:

      【解决方案3】:

      有时我们需要处理不符合 Java 命名标准的数据。能够做这样的事情会很好:

      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);
          }
      }
      

      需要修改“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;
      }
      

      【讨论】:

      • 1 个问题,为什么不让客户端代码先执行 valueOf 字符串,然后比较生成的 Enum?这样我们仍然在比较 Enums 并且我们不需要在 equals 和 hasCodes 周围烦恼
      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        我必须承认枚举是我最不想覆盖 equals() 的东西。

        我认为equals()在枚举中是final的原因是Java鼓励==进行枚举比较,而equals()在枚举中的实现只是使用它,所以允许equals()被覆盖是为了防止@ 987654326@ 和 equals() 的行为不同,这是其他开发人员无法预料的。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-11-05
          • 1970-01-01
          • 2016-07-12
          • 1970-01-01
          • 1970-01-01
          • 2013-07-05
          相关资源
          最近更新 更多