在Groovy中动态覆盖`equals`和`hashCode`

4
如果我动态覆盖一个类的equalshashCode方法,直接调用这些方法会调用重写的版本,但是在使用它们进行设置时,会使用未重写的版本。为什么会这样,并且是否仍然可以动态覆盖这两个方法以供所有用途使用?
class SuperClass {
  public boolean equals(Object other) {
    println 'non overridden equals called'
    false
  }

  public int hashCode() {
    println 'non overridden hashCode called'
    1
  }
}

SuperClass.metaClass.equals = { Object other ->
  println 'overridden equals called'
  true
}

SuperClass.metaClass.hashCode = { ->
  println 'overridden hashCode called'
  1
}

def a = new SuperClass()
def b = new SuperClass()

println a.hashCode() // overriden hashCode called
println b.hashCode() // overriden hashCode called
println a.equals(b) // overriden equals called

println([a, b].toSet().size()) // non overriden methods called, returns 2 instead of 1

你在元类中重写了 Set 的 equals() 和 hashcode() 方法吗? - Will
1
为什么我需要重写 Setequalshashcode 方法? - tig
抱歉,我只读了一半的问题 :-) - Will
1个回答

3

在一个List上调用toSet()会调用以下代码

    Set<T> answer = new HashSet<T>(self.size());
    answer.addAll(self);
    return answer;

现在,HashSet(Java类)没有metaClass的概念,因此无法看到您重载的hashCodeequals方法。因此,您的集合中会有两个项目。
您可以首先在列表上调用unique
println( [a, b].unique().toSet().size() ) 

作为这个过程通过调用者,所以知道关于metaClass,并应该给你一个包含一个元素的集合。
实际上,我会避免通过metaClass更改hashCode方法。如您所见,很难知道它将在何时处理,而处理得好的事情可能不会期望hashCode从一刻到另一刻发生变化。

那么使用Groovy就没有办法覆盖方法,以便Java类能够看到更改吗? - tig
Java类不知道metaClass,所以是的,除非Java代码使用Groovy调用程序或检查元类本身,否则更改将不会被Java代码看到。 - tim_yates
在动态覆盖toString()方法时也存在类似的问题。http://jira.codehaus.org/browse/GROOVY-2599 - bdkosher

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接