#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
тем не менее, это может быть полезно в качестве вдохновения при выполнении этого.