类从类型 java.util.Set 和 java.util.List 中继承 spliterator() 的不相关默认值

17

我有一个实现了 Set 和 List 接口的类。在 Java6 和 Java7 中程序可以正常工作。

public class SetList<V> implements Set<V>, List<V>
{
  ....
}

使用Java 8,这段代码无法编译。出现的错误信息如下:

java: 类 trials.SetList 继承了不相关的默认项 spliterator(),来自于类型 java.util.Set 和 java.util.List

错误信息指向的位置是 java/util/Set.java 的第 394 行。

 ...
@Override
default Spliterator<E> spliterator() {
    return Spliterators.spliterator(this, Spliterator.DISTINCT);
}

java/util/List.java

...
@Override
default Spliterator<E> spliterator() {
    return Spliterators.spliterator(this, Spliterator.ORDERED);
}

这是否意味着我不能在Java 8中实现既是Set又是List的类?(看起来是时候还我们的技术债了。)


5
请提供您自己的spliterator()实现。 - Sotirios Delimanolis
6
一个类如何同时实现Set和List? 这两者的合同是相互矛盾的。这听起来像是一个非常糟糕的主意。 - JB Nizet
@Sotirios Delimanolis - 谢谢,那可能就是答案了。 - Jayan
2
它将解决编译问题,但问题实际上是@JBNizet所说的。 - Sotirios Delimanolis
2
您无法在 Java 的 任何 版本中正确实现 SetList 两者。 - Louis Wasserman
显示剩余2条评论
3个回答

12

虽然一个类同时实现ListSet是不寻常的,但在某些情况下,一个Set也可以支持成为一个有限制的List

个人而言,在这种情况下,我更喜欢声明一个asList()方法,而不是同时实现ListSet。像这样:

public class SetList<V> implements Set<V> {
    public List<V> asList(){
        // return a list representation of this Set
    }
}

另一方面,如果您已经有一个实现了ListSet的现有类,则解决您的问题的最简单方法可能是显式调用其中一个超级spliterator()方法:

public class SetList<V> implements Set<V>, List<V> {
    @Override
    public Spliterator<V> spliterator() {
        return List.super.spliterator();
    }
}

10
这是关于多重继承中出现的菱形继承问题
“菱形问题”(有时也称为“死亡之菱形”)是一种模糊性,当两个类B和C从A继承,并且类D同时从B和C继承时,会出现这种情况。如果在A中有一个方法被B和C覆盖了,而D没有覆盖它,那么D将继承哪个版本的方法:B的版本还是C的版本?
在Java中,编译错误可以避免这个问题。要解决这个问题,您应该实现自己的解决方案。

0
在我的情况下,我在我的 ListSet 类中使用多个基础列表和集合。
由于我已经实现了 size()iterator() 方法(使用 Guava 的 Iterators.concat),最简单的解决方案是使用接受 Iterator 和大小的 Spliterators.spliterator() 重载。
/**
 * A custom list container that combines a set of unchangeable items with a list of changeable ones.
 * An iterator {@link #iterator()} is available that will iterate first through the unchangeable
 * items and then through the changeable ones. {@link #size()} is the total combined size and
 * {@link #get(int)} can return either an item from the unchangeable list or the changeable one.
 *
 * @param <E>
 */
class ListSet<E> implements List<E>, Set<E> {
    @NonNull
    private final ImmutableList<E> mConstantItemsList;
    @NonNull
    private final ImmutableSet<E> mConstantItemsSet;
    @NonNull
    private final List<E> mVariableItems;

    ListSet(Set<E> constantItems) {
        mConstantItemsSet = ImmutableSet.copyOf(constantItems);
        mConstantItemsList = ImmutableList.copyOf(constantItems);
        mVariableItems = Lists.newArrayList();
    }

    @NonNull
    @Override
    public Iterator<E> iterator() {
        return Iterators.concat(mConstantItemsList.iterator(), mVariableItems.iterator());
    }

    @Override
    public int size() {
        return mConstantItemsList.size() + mVariableItems.size();
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    @Override
    public Spliterator<E> spliterator() {
        return Spliterators.spliterator(iterator(), size(), Spliterator.ORDERED | Spliterator.DISTINCT);
    }
}



网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接