【问题标题】:class inherits unrelated defaults for spliterator() from types java.util.Set and java.util.List类从 java.util.Set 和 java.util.List 类型继承了 spliterator() 不相关的默认值
【发布时间】:2014-03-30 17:02:51
【问题描述】:

我有实现 Set 和 List 的类。程序在 Java6 和 Java7 中运行良好

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

对于 Java 8,这不会编译。错误是

java: 类 trial.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 的类? (看来是时候偿还我们的技术债务了。)

【问题讨论】:

  • 提供你自己的spliterator()实现。
  • 一个类如何实现Set和List?他们有相互矛盾的合同。这听起来是个非常糟糕的主意。
  • @Sotirios Delimanolis - 谢谢,这可能是答案
  • 它将解决编译问题,但问题确实是@JBNizet 所说的。
  • 你不能在任何版本的Java中正确实现SetList

标签: java java-8 technical-debt


【解决方案1】:

虽然一个类同时实现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();
    }
}

【讨论】:

    【解决方案2】:

    这是Diamond Problem that causes in Multiple inheritance

    “钻石问题”(有时被称为“致命的钻石问题”) 死亡”) 是当两个 B 类和 C 类时出现的歧义 从 A 继承,而 D 类同时从 B 和 C 继承。如果有 B 和 C 已覆盖的 A 中的方法,而 D 不会覆盖它, 那么 D 继承了哪个版本的方法:B 的那个,或者 B 的那个 C?

    在 Java 中,编译错误可以防止这个问题。为了解决这个你应该实现你的一个

    【讨论】:

      【解决方案3】:

      就我而言,我在 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);
          }
      }
      
      
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-18
        • 1970-01-01
        • 2018-05-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多