为通用集合编写contains()

Vik*_*ahl 4 java generics collections

我正在用java编写一个skiplist类作为练习.我写了一个名为SkipListInternal<E>包含实际跳过列表的类.我还创建了一个包装器类SkipListSet<E>,它实现了SortedSet<E>接口并包含一个实例SkipListInternal<E>.

除其他外,SkipListInternal<E>包含一个E find(E e)返回元素的方法,e如果它存在,则返回null,否则返回null.

在编写boolean contains(Object o)(继承自Collection<E>via SortedSet<E>)方法时,我注意到它的参数是一个Object而不是E.我打算做这样的事情,但由于类型擦除而不可能:

public class SkipListSet<E> implements SortedSet<E>{
   private SkipListInternal<E> skiplist;

   ...

   public boolean contains(Object o){
       if (!(o instanceof E)) return false;
       return skiplist.find((E) o) != null;
   }

   ...

}
Run Code Online (Sandbox Code Playgroud)

既然不能这样做,我该怎么做呢?

Joa*_*uer 8

严格来说,这样的实施是错误的.

这样做的原因是,即使对象不是类型E,它仍然可以trueequals()通话时返回.

假设你有一个这样的课:

public class FakeString {
  private final String value;

  public FakeString(String value) {
    if (value == null) {
      throw new IllegalArgumentException();
    }
    this.value = value;
  }

  public int hashCode() {
    return value.hashCode();
  }

  public boolean equals(Object o) {
    return value.equals(o);
  }
}
Run Code Online (Sandbox Code Playgroud)

然后这段代码将打印出来true:

List<String> strings = Arrays.asList("foo", "bar", "baz");
System.out.println(strings.contains(new FakeString("bar")));
Run Code Online (Sandbox Code Playgroud)

并且只是为了澄清:这种行为是有意的,并且是为什么contains()需要Object代替E.remove()顺便说一句,情况也是如此.

  • 这是真的有意吗?`equals`的规则要求实现是对称的,但是你的`FakeString`打破了这条规则.所有内置的`SortedSet`实现(`TreeSet`,来自java.util.concurrent的跳过列表实现)使用Comparator/Comparable并且根本不调用`equals`. (8认同)