2013-06-20 74 views
3

如果我动态地替代类的equalshashCode方法,则直接调用这些方法调用被覆盖的版本,但将它们用于set将使用未覆盖的版本。为什么它是这样,是否仍然有可能为所有用法动态重写这两种方法?在groovy中动态覆盖`equals`和`hashCode`

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 
+0

你在哪里重写了元类中Set的equals()和hashcode()? – Will

+1

为什么我需要重写'Set'的equals和'hashcode'? – tig

+0

对不起,有一半人读到这个问题:-) – Will

回答

2

调用上toSet()一个Listinvokes the following code

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,应该给你一个包含元素的集合。

实际上,我会避免通过metaClass更改hashCode方法。正如你所看到的,很难确切地知道它何时会被处理,而且处理得很好的事情可能并不指望hashCode会随时改变。

+0

所以用groovy没有办法重写方法,所以Java类会看到变化吗? – tig

+0

Java类不知道'metaClass',所以是的,Java代码将看不到变化(除非它正在通过使用Groovy调用程序或检查元类本身来寻找它) –

+0

当它有一个类似的问题时来动态覆盖toString()方法。 http://jira.codehaus.org/browse/GROOVY-2599 – bdkosher

相关问题