Java equals():反映或不反映

时间:2008-09-23 23:44:01

标签: java reflection equals

此问题特别与覆盖具有大量字段的对象的equals()方法有关。首先,让我说这个大型对象不能在不违反OO原则的情况下分解为多个组件,因此告诉我“没有类应该有超过x个字段”将无济于事。

接下来,当我忘记检查其中一个字段是否相等时,问题就出现了。因此,我的equals方法不正确。然后我想用反射:

--code removed because it was too distracting--

这篇文章的目的不一定是重构代码(这甚至不是我正在使用的代码),而是要获得关于这是否是一个好主意的输入。

优点:

  • 如果添加了新字段,则会自动包含该字段
  • 如果陈述
  • ,该方法远比30多简洁

缺点:

  • 如果添加了新字段,则会自动包含该字段,有时这是不合需要的
  • 性能:这一点要慢一些,我觉得不需要打破一个分析器
  • 将某些字段列入白名单以便在比较中忽略,这有点难看。

有什么想法吗?

9 个答案:

答案 0 :(得分:13)

如果您出于性能原因确实想要列入白名单,请考虑使用注释来指示要比较的字段。此外,如果您的字段没有equals()的良好实现,则此实现将不起作用。

P.S。如果你走equals()这条路线,不要忘记为hashCode()做类似的事情。

P.P.S。我相信您已经考虑过HashCodeBuilderEqualsBuilder

答案 1 :(得分:9)

使用Eclipse,FFS!

删除hashCode并使用等于你的方法。

右键单击该文件。

选择来源 - >生成哈希码并等于...

完成!不再担心反思。

对添加的每个字段重复一遍,只需使用大纲视图删除两个方法,然后让Eclipse自动生成它们。

答案 2 :(得分:5)

如果你采用反思方法,EqualsBuilder仍然是你的朋友:

 public boolean equals(Object obj) {
    return EqualsBuilder.reflectionEquals(this, obj);
 }

答案 3 :(得分:2)

如果你担心,这是一个想法:

1 /在添加/删除字段时,忘记更新大系列的if语句以检查相等性。

2 /在equals()方法中执行此操作的性能。

尝试以下方法:

a /恢复使用equals()方法中的if语句的长序列。

b /具有单个函数,其中包含字段列表(在字符串数组中),并且将根据实际情况检查该列表(即反射字段)。如果它们不匹配,它将抛出异常。

c /在此对象的构造函数中,对此函数进行同步的run-once调用(类似于单例模式)。换句话说,如果这是该类构造的第一个对象,则调用上面(b)中描述的检查函数。

如果您没有更新if语句以匹配反射字段,则在运行程序时,例外会立即显现;然后你修复if语句并从上面的(b)更新字段列表。

对象的后续构造不会进行此检查,并且您的equals()方法将以最大可能的速度运行。

尽可能地尝试,我无法找到这种方法的任何实际问题(StackOverflow上可能存在更多的思想) - 对于一次运行行为,每个对象构造都有一个额外的条件检查但是看起来相当公平次要的。

如果你努力尝试,你仍然可以使用你的字段列表和反射字段来获取你的if语句,但例外情况将确保你的字段列表与反射字段匹配,你只需确保更新if-声明和字段列表同时显示。

答案 4 :(得分:1)

您可以随时在equals方法中注释您/不想要的字段,这应该是一个简单而简单的更改。

性能显然与实际比较对象的频率有关,但很多框架都使用哈希映射,所以你的等号可能比你想象的更多。

另外,谈到哈希映射,hashCode方法也存在同样的问题。

最后,你真的需要比较所有字段是否相等?

答案 5 :(得分:1)

您的代码中有一些错误。

  1. 您不能认为thisobj是同一个类。实际上,它明确允许obj成为任何其他类。您可以从if ( ! obj instanceof myClass ) return false;开始,但这仍然不正确,因为obj可能是this的子类,其他字段可能很重要。
  2. 您必须使用简单null
  3. 支持obj的{​​{1}}值
  4. 您不能将if ( obj == null ) return false;和空字符串视为相等。而是特别对待null。这里最简单的方法是首先比较null。如果它们都相等或者两者都碰巧指向同一个对象,那么这很快。 (注意:这也是一个优化,您需要这是一个缓慢的例程。)如果失败,您可以使用快速Field.get(obj) == Field.get(this)来处理只有if ( Field.get(obj) == null || Field.get(this) == null ) return false;的情况。最后,您可以使用通常的null
  5. 您没有使用equals()
  6. 我同意汉克的观点,foundMismatch[HashCodeBuilder][1]是更好的方法。它很容易维护,而不是很多样板代码,你可以避免所有这些问题。

答案 6 :(得分:1)

您可以使用注释从支票中排除字段

e.g。

@IgnoreEquals
String fieldThatShouldNotBeCompared;

当然,您可以检查通用等于方法中是否存在注释。

答案 7 :(得分:0)

如果您可以访问这些字段的名称,为什么不将它们作为标准,您不想包含的字段始终以“local”或“nochk”或类似的字体开头。

然后你将所有以此开头的字段列入黑名单(代码不那么难看)。

我不怀疑它有点慢。您需要决定是否要根据执行速度交换易用性。

答案 8 :(得分:-1)