Java 8:Spliterator、Iterator、Collection和接口中的“default”实现(重复命名为spliterator的方法)

13

在Java 1.8.0_25发布后,我遇到了一个有趣的情况...... 我相信我的问题根源主要与接口中新的(对于1.8而言)“默认”实现特性有关。

我正在处理的应用程序目前针对1.7进行了优化,并一直运行良好。但是当用户开始升级到1.8时,我们被迫要支持1.8。

我们已经解决了大部分问题(主要涉及JavaFX包在1.7和1.8之间的更改),但仍有一个棘手的问题留下。

在我早些时候创造了一个从AbstractList<T>扩展的SortedList<T>类,这个类到目前为止一直工作正常,但在1.8的运行时环境下运行时,会出现以下错误:

Duplicate methods named spliterator with the parameters () and () are inherited 
from the types Collection<T> and Iterable<T>

在我看来,这似乎是由AbstractList<T>实现的某些接口中的“默认”实现引起的(我的SortedList<T>类没有实现除Serializable之外的任何其他接口)。对于我们来说,实现Serializable又是另一个问题,因为我们需要支持SortedList<T>对象的反序列化,这是无法避免的!

我可以通过在SortedList<T>类中提供spliterator()的重写实现来消除错误。然而,如果这样构建,它就不能在Java 1.7环境上运行。如果我尝试在1.7的运行时环境中使用SortedList<T>,我会得到以下错误:

Problem:
Error: Unresolved compilation problems:
The import java.util.Spliterator cannot be resolved
Spliterator cannot be resolved to a type

com.xxxx.xxxx.util.SortedList.<init>(SortedList.java:13) 

这个错误很明显,因为我们现在已经覆盖了SortedList<T>中的spliterator()方法,它需要包含java.util.Spliterator,但在1.7中不存在。

理想情况下,如果客户不想更新到Java 1.8,我们希望不要让他们强制更新。

这里是否有迫使我们的手?我们需要强制用户更新到1.8并向任何自行更新到1.8的用户发布新版本吗?

有谁知道如何解决这个问题吗?

在更深层次上,为什么Interface被实现污染了 :-(。这可能是一个巧妙的新功能,但他们确实应该避免做任何导致破坏现有代码的更改,特别是在如列表/集合等基本功能中。

对于这种困境的任何帮助或建议将不胜感激。

谢谢,

马克


3
由于 Collection<T> 扩展自 Iterable<T>,所以不应该出现“重复方法”错误。这是编译器出现问题的指示。请记住,即使您没有使用 Java 8 源代码或目标级别,在使用 Java 8 类时也需要一个Java 8意识的编译器。 - Holger
嗯,我以为我们已经解决了所有这方面的问题,现在必须再三检查并重试。感谢您的建议。 - Gumbatron
3个回答

2

默认方法的整个意义在于避免您所描述的情况。以下代码在Java 7和8中编译并按预期运行:

public class SortedList<T> extends AbstractList<T> implements Serializable {
  @Override public T get(int index) { return null; }
  @Override public int size() { return 0; }

  public static void main(String[] args) {
    SortedList<String> s = new SortedList<> ();
    System.out.println(s.size());
  }
}

这正是我所想的。可能是编译器问题,就像@Holger在上面建议的那样。 - Gumbatron

2

好的,@Holger和@assylias两位都是正确的...但是我们的情况有点复杂。

我们正在使用的环境是Eclipse 3.8.1,它不支持Java 8(据我所知,将来也不会)。因此,我们不能仅仅更改为Java 8编译器来解决问题。

我们的产品是一个相当大的Eclipse RCP应用程序。由于需要进行大量的重构工作,升级我们的IDE目前不是一个可行的选择。因此,我们将需要在Java 1.7环境下继续开发。

如果有人感兴趣,我们已经通过以下方式解决了这个问题:

  • 为我们的主插件创建片段(每个引起问题的Java版本一个,我们的情况下有三个)。这些片段被配置为补丁片段。
  • 将Java FX JAR文件添加到片段中(这是为了解决早期版本中Java FX的一些问题,以及1.8.0_25版本)。
  • 同样在片段中,在与主插件相同的命名空间中,我们添加了SortedList类的实现。对于每种情况,代码都是相同的,但是针对Java 8编译器编译的片段是特定的。最终并不需要覆盖spliterator()方法(当使用Java 8编译器编译时,它可以正常工作,并且仍然可以使用1.7编译器编译,因为不再有对Spliterator类的引用)。

这可能不是一个理想的解决方案,但我们认为它会起作用 :-)

感谢您的意见和建议,非常感谢。


0
尝试创建一个抽象类,该类使用首选行为定义重写spliterator()。
abstract class Java8_AbstractCollection<E> extends AbstractCollection<E> {

    /* (non-Javadoc)
     * @see java.util.Collection#spliterator()
     */
    public Spliterator<E> spliterator() {
        return (Spliterator<E>) super.spliterator();
    }
}

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