4

如果我为一个类动态覆盖equalshashCode方法,调用这些方法直接调用覆盖的版本,但将它们用于 set 使用非覆盖版本。为什么会这样,是否仍然可以为所有用法动态覆盖这两种方法?

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
4

1 回答 1

3

调用toSet()aList 调用以下代码

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

现在HashSet(Java 类)没有 的概念metaClass,因此看不到您的重载hashCodeequals方法。因此,您会在您的套装中获得 2 件物品。

你可以做的是unique首先在你的名单上打电话:

println( [a, b].unique().toSet().size() ) 

当这通过调用者时,所以知道metaClass并且应该给你一个包含一个元素的集合。

在实践中,我会避​​免hashCode通过 metaClass 更改方法。正如您所看到的,很难确切知道它何时会被处理,并且处理得好的事情可能不会期望 hashCode 时时发生变化。

于 2013-06-20T10:14:32.337 回答