В стандартной библиотеке Java значение LinkedHashSet
совпадает с HashSet
, но с предсказуемым порядком итерации (порядок вставки). Мне нужен IdentityHashSet
(который использует идентификатор объекта или ссылочное равенство вместо равенства объектов) с предсказуемым порядком итерации (порядок вставки).
Хотя в стандартной библиотеке Java нет IdentityHashSet
, вы можете легко создать ее, используя доступную IdentityHashMap
, с помощью следующего оператора:
Set<T> identitySet = java.util.Collections.newSetFromMap(new IdentityHashMap<>());
Это почти та же самая реализация, которая используется в Guava's Sets.newIdentityHashSet()
; но это имеет неопределенное, обычно хаотическое расположение ключей HashMap
(и HashSet
элементов).
Мои поиски реализации IdentityLinkedHashSet
не дали результатов, поэтому я решил реализовать ее самостоятельно. Один полезный результат, который я нашел, был этот ответ , который предлагает использовать класс-оболочку для идентификации в композиции с LinkedHashSet
.
Я пытался реализовать эту идею. Ниже приведен ключевой фрагмент моей реализации. Полный доступ к Gist можно получить здесь .
public class IdentityLinkedHashSet<E> implements Set<E> {
private LinkedHashSet<IdentityWrapper> set;
/* ... constructors ... */
@Override
public boolean add(E e) {
return set.add(new IdentityWrapper(e));
}
@Override
public boolean contains(Object obj) {
return set.contains(new IdentityWrapper((E) obj));
}
/* ... rest of Set methods ... */
private class IdentityWrapper {
public final E ELEM;
IdentityWrapper(E elem) {
this.ELEM = elem;
}
@Override
public boolean equals(Object obj) {
return obj != null && ELEM == obj;
}
@Override
public int hashCode() {
return System.identityHashCode(ELEM);
}
}
}
Затем я написал несколько юнит-тестов для проверки моей реализации. К сожалению, некоторые из утверждений не удаются! Вот мои тесты:
String str1 = new String("test-1");
String str2 = new String("test-2");
String str3 = new String("test-2");
Set<String> identitySet = new IdentityLinkedHashSet<>();
assertTrue(idSet.add(str1));
assertFalse(idSet.add(str1)); // <-- fails!
assertTrue(idSet.contains(str1)); // <-- fails!
//
assertTrue(idSet.add(str2));
assertFalse(idSet.add(str2)); // <-- fails!
assertTrue(idSet.contains(str2)); // <-- fails!
assertFalse(idSet.contains(str3));
//
assertTrue(idSet.add(str3));
assertFalse(idSet.add(str3)); // <-- fails!
assertTrue(idSet.contains(str3)); // <-- fails!
assertEquals(3, idSet.size()); // <-- fails!
Что я сделал не так в этой реализации?