通过包装 LinkedHashSet 实现 IdentityLinkedHashSet

在 Java 标准库中,aLinkedHashSet与 a 相同,HashSet但具有可预测的迭代顺序(插入顺序)。我需要一个IdentityHashSet具有可预测迭代顺序(插入顺序)的(使用对象标识或引用相等,而不是对象相等)。


虽然IdentityHashSetJava 的标准库中没有,但您可以使用IdentityHashMap以下语句轻松创建一个:


Set<T> identitySet = java.util.Collections.newSetFromMap(new IdentityHashMap<>());

这与 Guava 中使用的实现几乎相同Sets.newIdentityHashSet();但这具有未指定的,通常是混乱的HashMap键(和HashSet元素)顺序。


我对 an 实现的搜索IdentityLinkedHashSet没有结果,所以我决定自己实现它。我发现的一个有用的结果是这个答案,它建议使用一个身份包装类与LinkedHashSet.


我试图实现这个想法。下面是我的实现的一些关键片段。在此处访问完整的要点。


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!

我在这个实现中做错了什么?


紫衣仙女
浏览 120回答 1
1回答

繁星淼淼

调用IdentityWrapper.equals()方法时。LinkedHashSet不会传递的而是ELEM一个IdentityWrapper对象。您必须引入额外的检查 ( instanceOf),然后打开传递的对象以比较元素:public boolean equals(Object obj) {&nbsp; &nbsp; return (obj instanceof IdentityLinkedHashSet<?>.IdentityWrapper) &&&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; ELEM == ((IdentityLinkedHashSet<?>.IdentityWrapper) obj).ELEM;}一些注意事项:instanceof将检查 null,因此您可以完全删除该检查。你必须IdentityWrapper像这样引用:IdentityLinkedHashSet<?>.IdentityWrapper因为它不是一个static类。如评论中所述。可以将其设为静态,并且可以将其类型ELEM从 更改E为Object。您还会用更好的equals方法离开哪个:private static class IdentityWrapper {&nbsp; &nbsp; public final Object ELEM;&nbsp; &nbsp; IdentityWrapper(Object elem) {&nbsp; &nbsp; &nbsp; &nbsp; this.ELEM = elem;&nbsp; &nbsp; }&nbsp; &nbsp; @Override&nbsp; &nbsp; public boolean equals(Object obj) {&nbsp; &nbsp; &nbsp; &nbsp; return (obj instanceof IdentityWrapper) && ELEM == ((IdentityWrapper) obj).ELEM;&nbsp; &nbsp; }&nbsp; &nbsp; @Override&nbsp; &nbsp; public int hashCode() {&nbsp; &nbsp; &nbsp; &nbsp; return System.identityHashCode(ELEM);&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java