Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/401.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在java枚举中重写(final)equals方法?_Java_Enums_Overriding_Equals_Final - Fatal编程技术网

如何在java枚举中重写(final)equals方法?

如何在java枚举中重写(final)equals方法?,java,enums,overriding,equals,final,Java,Enums,Overriding,Equals,Final,我在覆盖枚举中的equals方法以使其与其他类兼容时遇到问题。 Enum实现了一个接口,其思想是可以对该接口的所有实现进行平等性测试,而不管它们的类型如何。例如: public interface Group { public Point[] getCoordinates(); } public enum BasicGroups implements Group { a,b,c; // simplified, they actually have constructors

我在覆盖枚举中的equals方法以使其与其他类兼容时遇到问题。 Enum实现了一个接口,其思想是可以对该接口的所有实现进行平等性测试,而不管它们的类型如何。例如:

public interface Group {
    public Point[] getCoordinates();
}

public enum BasicGroups implements Group {
    a,b,c; // simplified, they actually have constructors
    // + fields and methods
}

public class OtherGroup implements Group {
    // fields and methods
}
如果
BasicGroup
OtherGroup
具有相同的坐标(以任意顺序),则equals方法应返回true

执行
myOtherGroup.equals(BasicGroup.a)
时没有问题,但是由于Enums中的equals方法是final,因此我无法重写它们


有办法解决这个问题吗?与在另一个BasicGroup上测试时一样,使用默认的equals方法(引用相等),在测试其他类时使用我自己的实现。当我使用
BasicGroup.a.equals(myOtherGroup)
时,如何确保java不会使用错误的方法?

在java中不可能这样做。(当谈到方法时,final关键字的唯一目的是防止重写!)

equals
和枚举上的其他一些方法是final,因此您无法更改它们的行为。(你不应该:)以下是我对一个问题的答案:


处理枚举常量的客户端的直觉是,两个常量
相等
当且仅当它们是相同的常量时。因此,除了
返回this==other
之外的任何其他实现都会违反直觉且容易出错

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

JLS并没有激发最终选择的动机,但在枚举的上下文中提到了equals。片段:

Enum中的equals方法是最后一个方法,它仅对其参数调用super.equals并返回结果,从而执行标识比较


您可以通过调用方法HassameCoordinates或类似方法而不是equals来解决此问题

Enum的equals在语言规范中定义,因此您不能希望重新定义它。

您不能
@重写
a
final
方法();这一点很清楚<代码>枚举
类型()在Java中得到了非常特殊的处理,这就是为什么
equals
最终的
(还有
克隆
哈希代码
,等等)根本不可能
@重写
枚举
equals
方法,在更典型的使用场景中也不可能

但是,从全局来看,您似乎正在尝试遵循有效Java第二版第34项:使用接口模拟可扩展枚举中推荐的模式(有关
enum
的更多信息,请参阅):

您已经定义了此
接口
(现在明确记录了预期的
等于
行为):

当然,
接口
定义实现者的
equals
方法的行为方式是完全可以接受的。这正是,例如。空的
链接列表
等于空的
数组列表
,反之亦然,因为
接口
要求这样做

在您的例子中,您选择将一些
实现为
枚举
。不幸的是,您现在无法按照规范实现
equals
,因为它是
最终的
,您无法
@覆盖它。但是,由于目标是遵守
类型,您可以通过使用
转发组
来使用,如下所示:

public class ForwardingGroup implements Group {
   final Group delegate;
   public ForwardingGroup(Group delegate) { this.delegate = delegate; }

   @Override public Point[] getCoordinates() {
       return delegate.getCoordinates();
   }
   @Override public boolean equals(Object o) {
       return ....; // insert your equals logic here!
   }
}
现在,您不用将
枚举
常量直接用作
,而是将它们包装在
转发组
的实例中。现在,此
对象将具有所需的
等于
行为,如
接口
所指定

也就是说,而不是:

// before: using enum directly, equals doesn't behave as expected
Group g = BasicGroup.A;
您现在有了类似于:

// after: using decorated enum constants for proper equals behavior
Group g = new ForwardingGroup(BasicGroup.A);

附加说明
enum BasicGroups实现了Group
,尽管它本身并不遵循
Group.equals
的规范,但这一事实应该被清楚地记录下来。必须提醒用户,常数必须包装在
ForwardingGroup
中,以实现正确的
equals
行为

还请注意,您可以缓存
ForwardingGroup
的实例,每个
enum
常量对应一个实例。这将有助于减少创建的对象数量。根据有效的java第二版,项目1:考虑静态工厂方法而不是构造函数,可以考虑使用<代码>转发组>代码>定义一个代码>静态GETSimple(组G)< /C>方法,而不是一个构造函数,允许它返回缓存实例。 我假设
Group
是一种不可变类型(有效的Java第二版,第15项:最小化可变性),否则您可能不应该首先使用
enum
实现它。鉴于此,考虑有效的java第二版,项目25:喜欢列表到数组。您可以选择让
getCoordinates()
返回
列表,而不是
点[]
。您可以使用(另一个decorator!),这将使返回的
列表不可变。相比之下,由于数组是可变的,因此在返回
点[]
时,您将被迫执行防御性复制

另见

    • 平等是相当难以捉摸的。不同的语境需要不同的平等关系。通过在对象上使用equals()方法,Java强加了一个“内在”等式,API和Set一样依赖于它

      同时,排序并不被认为是“内在的”,两个对象可以在不同的上下文中进行不同的排序,API通常允许我们提供一个压缩机,即自定义排序关系

      这是
      // after: using decorated enum constants for proper equals behavior
      Group g = new ForwardingGroup(BasicGroup.A);
      
      interface Equalator
          boolean equal(a, b)
      
      public HashSet( Equalator equalator )