为了账号安全,请及时绑定邮箱和手机立即绑定

通过包装 LinkedHashSet 实现 IdentityLinkedHashSet

通过包装 LinkedHashSet 实现 IdentityLinkedHashSet

紫衣仙女 2022-05-12 15:39:55
在 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!我在这个实现中做错了什么?
查看完整描述

1 回答

?
繁星淼淼

TA贡献1775条经验 获得超11个赞

调用IdentityWrapper.equals()方法时。LinkedHashSet不会传递的而是ELEM一个IdentityWrapper对象。


您必须引入额外的检查 ( instanceOf),然后打开传递的对象以比较元素:


public boolean equals(Object obj) {

    return (obj instanceof IdentityLinkedHashSet<?>.IdentityWrapper) && 

        ELEM == ((IdentityLinkedHashSet<?>.IdentityWrapper) obj).ELEM;

}

一些注意事项:


instanceof将检查 null,因此您可以完全删除该检查。

你必须IdentityWrapper像这样引用:IdentityLinkedHashSet<?>.IdentityWrapper因为它不是一个static类。如评论中所述。可以将其设为静态,并且可以将其类型ELEM从 更改E为Object。您还会用更好的equals方法离开哪个:


private static class IdentityWrapper {


    public final Object ELEM;


    IdentityWrapper(Object elem) {

        this.ELEM = elem;

    }


    @Override

    public boolean equals(Object obj) {

        return (obj instanceof IdentityWrapper) && ELEM == ((IdentityWrapper) obj).ELEM;

    }


    @Override

    public int hashCode() {

        return System.identityHashCode(ELEM);

    }

}


查看完整回答
反对 回复 2022-05-12
  • 1 回答
  • 0 关注
  • 119 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信