2013-06-20 5 views
3

Если я динамически переопределяю equals и hashCode методы для класса, вызов этих методов напрямую вызывает переопределенные версии, но с их использованием для set использует неперекрываемые версии. Почему это так, и все еще возможно динамически переопределять эти два метода для всех применений?Динамически переопределять `equals` и` hashCode` в groovy

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

Где вы переопределили equals() и set 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, и поэтому не видит ваши перегруженные hashCode и equals методы. Поэтому вы получаете 2 предмета в своем наборе.

Что вы можете сделать, это вызов unique в списке в первую очередь:

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

Как это проходит через запустившего так знает о metaClass и должно дать вам множество, содержащее один элемент.

На практике я бы не стал менять метод hashCode через metaClass. Как вы можете видеть, трудно точно знать, когда это будет обрабатываться, и все, с чем он справляется, может не ожидать изменения хеш-кода от момента к моменту.

+0

Итак, с groovy нет способа переопределить методы, поэтому изменение будет видно классам Java? – tig

+0

Java-классы не знают о 'metaClass', так что да, это изменение не будет видно по Java-коду (если только он не ищет его с помощью вызова Groovy или проверки самого метакласса) –

+0

Существует также аналогичная проблема, когда динамически переопределяет методы toString(). http://jira.codehaus.org/browse/GROOVY-2599 – bdkosher

Смежные вопросы