【发布时间】:2010-02-05 07:11:26
【问题描述】:
我们有一个 OO 代码库,在很多情况下 hashcode() 和 equals() 根本不起作用,主要是因为以下原因:
没有办法扩展 可实例化的类并添加一个值 组件,同时保留等式 合同,除非你愿意 放弃面向对象的好处 抽象。
这是 Joshua Bloch 的“Effective Java”中的一段引述,关于该主题的更多信息请参见此处的一篇精彩的 Artima 文章:
http://www.artima.com/lejava/articles/equality.html
我们对此非常满意,这不是这个问题的目的。
问题是:看到在某些情况下您无法满足equals() 合同的事实,那么自动使hashcode() 和equals() 抛出UnsupportedOperationException 的干净方法是什么?
注释会起作用吗?我正在考虑类似@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 会起作用吗?
有趣的是,真正的问题是hashCode() 和equals() 出现在Java 层次结构的顶部,这在某些情况下根本没有意义。但是我们如何干净利落地处理这个问题呢?
【问题讨论】:
-
+1 用于在不需要的时候拒绝实现 hashCode 和 equals,甚至确保它们不能通过抛出异常来调用。这是对您经常听到的口头禅的一个可喜的变化,即您必须做的第一件事是实现这两种方法(并花很多心思在它们上以使它们正常工作),即使大多数对象从不需要任何一种方法。跨度>
-
当您编写实现接口的新类时,Eclipse 为您提供的自动生成方法的一个相关问题是它们都生成到
return null、return false、@987654336 @。我希望默认为throw UnsupportedOperationException("TODO")。 -
@Thilo 我用我的 Eclipse 模板就是这样做的,所有生成的方法体都会抛出
UnsupportedOperationException -
@Bemrose:我不同意。如果您想检查它们是否是相同的参考,请使用 ==(尽管我并不经常需要这样做,但确实没有害处),而不是 equals(),这将是非常有害的。因为你无法知道 equals() 方法是否被覆盖,所以依赖 Object 的默认 equals() 方法使用 == 而不是自己直接使用 == 是非常有害的。
-
@Thilo:我已经更改了我的 Eclipse 模板来做到这一点。它还添加了当前日期,因此我可以知道方法未实现多长时间。
标签: java equals design-by-contract