2017-01-25 1 views
3

В настоящее время я сталкиваюсь с сценарием, где у меня есть строковые кортежи (размером 2), а два кортежа должны считаться равными, если они имеют хотя бы один общий элемент. У меня есть следующий класс, реализующий эту идею:Метод hashCode() для следующего случая: два набора равны, если они имеют хотя бы один общий элемент?

public class MyTuple 
{ 
    private List<String> list = Arrays.asList(new String[2]); 

    public List<String> getList() 
    { 
     return list; 
    } 

    public void set(String firstElement, String secondElement) 
    { 
     list.set(0, firstElement); 
     list.set(1, secondElement); 
    } 

    @Override 
    public boolean equals(Object other) 
    { 
     if (other instanceof MyTuple) { 
      return !Collections.disjoint(this.list, ((MyTuple) other).getList()); 
     } 
     return false; 
    } 
} 

Однако, согласно hashCode() контракта:

Если два объекта равны по равных метод (Object), то вызов хэш-код() метод на каждом из двух объектов должен давать одинаковый целочисленный результат.

Как я могу переопределить мой метод hashCode(), чтобы не нарушать договор?

+0

Нет необходимости, потому что 'MyTuple' никогда не может быть ключевым в коллекции. –

+0

Почему бы и нет? Я использую Spark, и MyTuple будет ключом в парных RDD. – TrnKh

+1

Возвращает константу для hashCode(). Это, безусловно, приведет к повышению производительности при использовании MyTuple в любой коллекции, которая использует хэш-код, но с вашим «динамическим» правилом равенства это единственный способ удовлетворить контракт. – Durandal

ответ

5

Прежде чем рассматривать hashCode(), я думаю, вы должны сначала пересмотреть свой дизайн equals(). Я не думаю, что вы можете реализовать equals() и выполнить необходимый договор - особенно один на транзитивности

От: Java Doc of Object#equals()

Равных метод реализует отношение эквивалентности на непустых ссылок на объекты :

  • это рефлексивно: для любого ненулевого опорного значения х, x.equals (х) должна возвращать верно.

  • Он симметричен: для любых ненулевых эталонных значений х и у, x.equals (у) должна возвращать истинна тогда и только тогда, когда y.equals (х) возвращает истину.

  • Это является переходным: для любых ненулевых значений ссылок х, у, г, если x.equals (у) возвращает истинный и y.equals (г) возвращает истинный, затем x.equals (г) должен возвращать true.

  • Это соответствует: для любых ненулевых значений ссылок х и у, несколько призываний x.equals (у) последовательно возвращают истину или последовательно возвращать ложь, не представило информации, используемую в равных сравнения на объектах изменен.

  • Для любого ненулевого опорного значения х, x.equals (NULL) должен возвращать ложь.

Почему? Я могу построить три объекта из ваших MyTuple:

  • А = {x1, x2}
  • В = {х2, х3}
  • С = {x3, x4}

, где x1 , x2, , x4 все различны.Теперь у меня есть

  • a.equals (B) возвращает истинное
  • B.equals (C) возвращает истину
  • C.equals (A) возвращает ложь

И они нарушают договор на транзитивности.

Я думаю, вам стоит подумать о том, чтобы использовать другое собственное отношение (возможно, partialEquals()), поэтому вам не нужно подчиняться контракту. Но тогда вы не использовать метод как equals() и ожидать MyTuple работать, , например, в HashMap, HashSet и т.д.

+0

К сожалению, partialEquals() не поможет, так как мне нужно выполнить операции ByKey в Spark on MyTuple в качестве ключа. Все эти операции зависят от equals() и hasCode(). По-видимому, мне нужно переосмыслить это. Спасибо. – TrnKh

+0

@Tkh - Вы можете рассматривать ** канонизацию ** вашего 'MyTuple' путем сортировки элемента в' list' (по порядку), поэтому, если у вас есть '{x1, x2}' и '{x2, x1 } ', они всегда канонизируются как' {x1, x2} '(предполагая' x1 leeyuiwah

+0

@TKh - (продолжение ...) Не зная точного сценария приложения. Эта идея канонизации может или не может работать для вас. – leeyuiwah

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