为什么这在Java 7下编译,但在Java 8下却没有?

这似乎可以很好地编译Java 7,以及任何版本的Scala库:

public static void main(String[] args) {
    scala.collection.immutable.Set<String> set = new scala.collection.immutable.HashSet<String>();
    Iterator<String> iterator = set.iterator();
}

它也可以很好地编译Java 8和Scala 2.11.5 +。但是对于Java 8和Scala 2.11.4,Eclipse抱怨道:

The method iterator() is ambiguous for the type Set<String>

我不明白这一点。在某些上下文中,您可能会对选择哪种重载方法产生歧义,但是如果您没有传递任何参数,则肯定不会?

真正奇怪的是,如果我像这样重铸它:

public static void main(String[] args) {
    Iterator<String> iterator = new scala.collection.immutable.HashSet<String>().iterator();
}

然后投诉就消失了。在我看来,这与上面的版本完全相同。那么为什么它现在编译得很好呢?


答案 1

如果我们比较 的 javap 输出,我们得到 2.11.4 的 javap 输出:scala.collection.immutable.Set

public interface scala.collection.immutable.Set<A> 
    extends 
        scala.collection.immutable.Iterable<A>, 
        scala.collection.Set<A>, 
        scala.collection.generic.GenericSetTemplate<A, 
        scala.collection.immutable.Set>, 
        scala.collection.SetLike<A, scala.collection.immutable.Set<A>>, 
        scala.collection.Parallelizable<A, 
        scala.collection.parallel.immutable.ParSet<A>> {
    public abstract scala.collection.generic.GenericCompanion<scala.collection.immutable.Set> companion();
    public abstract <B> scala.collection.immutable.Set<B> toSet();
    public abstract scala.collection.immutable.Set<A> seq();
    public abstract scala.collection.parallel.Combiner<A, scala.collection.parallel.immutable.ParSet<A>> parCombiner();
}

对于 2.11.5:

public interface scala.collection.immutable.Set<A>
    extends 
        scala.collection.immutable.Iterable<A>, 
        scala.collection.Set<A> {
    public abstract scala.collection.generic.GenericCompanion<scala.collection.immutable.Set> companion();
    public abstract <B> scala.collection.immutable.Set<B> toSet();
    public abstract scala.collection.immutable.Set<A> seq();
    public abstract scala.collection.parallel.Combiner<A, scala.collection.parallel.immutable.ParSet<A>> parCombiner();
}

版本 2.11.4 不正确,它违反了 Java 虚拟机规范,第 4.7.9.1 节

类签名对有关(可能是泛型的)类声明的类型信息进行编码。它描述类的任何类型参数,并列出其(可能参数化的)直接超类和直接超接口(如果有)。类型参数由其名称描述,后跟任何类绑定和接口边界。


这在此 scalac 问题中得到了明确的解释,这些问题已在...2.11.5


答案 2

这可能不是一个严格的Java 8 / Scala库问题。它可能与Eclipse有关。您使用的是哪个版本的 Eclipse?这听起来有点像Eclipse 4.4中的这个问题:Java 8泛型认为单一方法是模棱两可的。


推荐