gpt4 book ai didi

java - 通过包装 LinkedHashSet 实现 IdentityLinkedHashSet

转载 作者:搜寻专家 更新时间:2023-11-01 03:15:39 24 4
gpt4 key购买 nike

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

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

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

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

我搜索 IdentityLinkedHashSet 的实现没有结果,所以我决定自己实现它。我发现的一个有用结果是 this answer ,这建议在组合中使用身份包装类 LinkedHashSet .

我试图实现这个想法。下面是我实现的一些关键片段。 Access the full Gist here .

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!

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

最佳答案

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

你必须引入一个额外的检查(instanceOf)然后打开传递的对象来比较元素:

public boolean equals(Object obj) {
return (obj instanceof IdentityLinkedHashSet<?>.IdentityWrapper) &&
ELEM == ((IdentityLinkedHashSet<?>.IdentityWrapper) obj).ELEM;
}

一些注意事项:

  1. instanceof将检查 null,因此您可以完全删除该检查。
  2. 您必须引用 IdentityWrapper像这样:IdentityLinkedHashSet<?>.IdentityWrapper因为它不是 static类(class)。如评论中所述。它可以设为静态,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);
    }
    }

关于java - 通过包装 LinkedHashSet 实现 IdentityLinkedHashSet,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54254292/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com