Реализации методов Google Guava / Equivalence / different equals() и hashCode()

#java #guava

#java #guava

Вопрос:

Я хочу иметь возможность переключаться между двумя реализациями equals, но я не уверен Equivalence , может ли класс Google Guava предоставлять эту функциональность. Допустим, у меня есть два метода equals equalsContent() и equalsKeys() или что-то в этом роде, я как-то хочу делегировать метод equals одному из двух частных методов (и то же самое для двух методов hashCode).

Ну, я как-то не уверен, каково использование Equivalence абстрактного класса и Equivalences класса (статические методы).

Кроме того, как бы вы реализовали желаемые свойства, описанные выше? Я мог бы использовать другой метод, который просто устанавливает флаг или перечисление для значения и реализует два метода equals и hash внутри перечисления с помощью двух абстрактных методов (equals(), hashCode()) и просто вызывает enum.equals() или enum.hashCode() в equals() иМетод hashCode(). Что вы думаете?

Ответ №1:

Я думаю, что подход enum имел бы смысл с объектно-ориентированной точки зрения, но это опасно. Это может нарушить equals() hashCode() контракт and (рефлексивность, симметрия и транзитивность). Например, вставка экземпляра, который использует первую стратегию эквивалентности, и экземпляра, который использует вторую стратегию эквивалентности в одном и том же Set , может вызвать проблемы.

Если вам нужны разные отношения эквивалентности, вы должны исключить их из своего класса. Equivalence позволяет вам сделать именно это: вы извлекаете логику эквивалентности (equals() / hashCode() ) путем реализации эквивалентности и переопределения методов doHash() and doEquivalent() .

Затем, когда вы хотите использовать a Collection на основе той или иной эквивалентности, вы используете Equivalence.wrap() . Например, вы могли бы эмулировать IdentityHashSet , выполнив:

 Set<Equivalence.Wrapper<String>> identityHashSet = Sets.newHashSet();

String a1 = "a";
String a2 = new String("a");
String b = "b";

identityHashSet.add(Equivalences.identity().wrap(a1));
identityHashSet.add(Equivalences.identity().wrap(a2));
identityHashSet.add(Equivalences.identity().wrap(a3));

// identityHashSet contains "a", "a", and "b"
// a standard HashSet would only contain "a" and "b"
// while a1 and a2 are equal according to String.equals(), they are different instances.
 

Конечно, вы могли бы использовать ForwardingSet для автоматизации переноса / разворачивания ваших элементов.

В этом выпуске Guava есть больше информации.

Комментарии:

1. Правда, спасибо, я даже не знал об обертке, но, возможно, это может быть потому, что я только что обновил Guava с r09 до 10 😉

2. Как вы могли бы использовать ForwardingSet для автоматизации упаковки / разворачивания? Если ваш класс расширяется ForwardingSet<Wrapper<E>> , он также не может быть реализован Set<E> .

3. Хороший момент. Вам нужно будет самостоятельно реализовать шаблон пересылки. ForwardingSet тем не менее, это может быть полезно в качестве вдохновения при выполнении этого.