Java:在调用 hashCode() 和 equals() 时自动抛出 UnsupportedOperationException 的干净方法?

2022-09-04 01:54:38

我们有一个OO代码库,在很多情况下根本不起作用,主要是因为以下原因:hashcode()equals()

没有办法在保留 equals 协定的同时扩展可实例化类并添加值组件,除非你愿意放弃面向对象抽象的好处。

这是Joshua Bloch的“Effective Java”中的一句话,在Artima的一篇很棒的文章中有更多关于这个主题的内容:

http://www.artima.com/lejava/articles/equality.html

我们对此完全没问题,这不是这个问题的意义所在。

问题是:看到在某些情况下您无法满足合同是事实,那么自动制作和抛出不支持的操作异常的干净方法是什么?equals()hashcode()equals()

注释是否有效?我正在考虑这样的事情:每次违反契约都会自动引发异常,除了用 注释参数/返回值之外,您没有其他事情可做。@NotNull@NotNull@NotNull

这很方便,因为它是8个字符(“@NotNull”),而不是不断重复相同的验证/抛出异常代码。

在我担心的情况下,在每一个没有意义的实现中,我们总是重复同样的事情:hashCode()/equals()

@Override
public int hashCode() {
    throw new UnsupportedOperationException( "contract violation: calling hashCode() on such an object makes no sense" );
}

@Override
public boolean equals( Object o ) {
    throw new UnsupportedOperationException( "contract violation: calling equals() on such an object makes no sense" );
}

然而,这很容易出错:我们可能会错误地忘记剪切/粘贴它,这可能会导致用户滥用这些对象(例如,尝试将它们放在默认的Java集合中)。

或者,如果无法进行注释以创建此行为,AOP 是否有效?

有趣的是,真正的问题是Java层次结构的存在和顶端的存在,这在某些情况下根本没有意义。但是,我们如何干净利落地处理这个问题呢?hashCode()equals()


答案 1

我同意你对这个问题的评估,首先是Object中的问题和定义。长期以来,我一直认为平等应该以与排序相同的方式处理 - 一个界面说“我可以与X的一个实例进行比较”,另一个说“我可以比较X的两个实例”。hashCodeequals

另一方面,这是否真的对您造成了任何错误?人们是否一直在尝试使用,以及他们不应该使用的地方?因为即使你可以让代码库中的每个类在调用这些方法时都抛出异常,但你正在使用的其他类(无论是来自 JDK 还是第三方库)都不是这样。equalshashCode

我相信你可以用某种形式的AOP来做到这一点,无论是正常的注释处理还是其他东西 - 但是你有证据表明奖励是值得的吗?

另一种看待它的方式:这仅在您扩展另一个已经覆盖和的类的情况下,对吗?否则,您可以使用 Object 的 hashCode/equals 方法的“equality = identity”性质,这仍然很有用。您是否有很多属于此类别的课程?你能不能只是写一个单元测试来通过反射找到所有这样的类型,并检查这些类型在你调用 /时是否抛出异常?(如果它们具有无参数构造函数,则可以自动执行此操作,或者具有已检查类型的手动列表 - 如果有新类型不在“已知良好”列表中,则单元测试可能会失败。hashCodeequalshashCodeequals


答案 2

我不明白为什么你认为“在某些情况下你不能满足equals()契约”?平等的含义由类定义。因此,使用 Object 的 equal 是完全有效的。如果您没有覆盖相等,那么您将每个实例定义为唯一的。

似乎有一种误解,认为equals是那些总是需要覆盖的方法之一,并且它必须检查其所有字段。我会提出相反的观点——除非你对平等的定义不同,否则不要推翻平等。

我也不同意artima的文章,特别是“陷阱#3:根据可变字段定义相等”。类基于可变字段定义其相等性是完全有效的。用户在将其与集合一起使用时应注意这一点。如果可变对象在其可变状态上定义了其相等性,则不要期望两个实例在一个实例更改后相等。

我认为抛出不支持的操作违反了平等的冲刺。对象的状态等于:

类 Object 的 equals 方法在对象上实现最有区别的可能等价关系;也就是说,对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一对象(x == y 的值为 true),此方法才返回 true。

因此,我应该能够调用 equals 并获取 true 或 false 值,具体取决于 Object 的 equals 定义或被覆盖的 equals 定义。


推荐