【问题标题】:Compilation failure when not overriding interface default implementation未覆盖接口默认实现时编译失败
【发布时间】:2020-02-01 10:45:26
【问题描述】:

我正在尝试实现org.apache.spark.sql.Row。接口有几种方法的默认实现,IntelliJ 不会抱怨没有覆盖这些方法。 但是,当使用 Maven 构建时,我得到:

FunctionalRow is not abstract and does not override abstract method mkString(java.lang.String,java.lang.String,java.lang.String) in org.apache.spark.sql.Row

下面是类的实现:

import java.util.List;
import java.util.function.Supplier;

import org.apache.spark.sql.Row;

import scala.collection.JavaConverters;
import scala.collection.Seq;

public class FunctionalRow implements Row {
    protected List<Supplier<Object>> suppliers;

    public FunctionalRow(List<Supplier<Object>> suppliers) {
        this.suppliers = suppliers;
    }

    @Override
    public int length() {
        return suppliers.size();
    }

    @Override
    public Object get(int i) {
        return suppliers.get(i).get();
    }

    @Override
    public Row copy() {
        return this;
    }

    @Override
    public Seq<Object> toSeq() {
        return JavaConverters.asScalaIteratorConverter(suppliers.stream().map(s -> s.get()).iterator()).asScala().toSeq();
    }
}

maven-compiler-plugin 设置:

        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
          <executions>
            <execution>
              <id>default-compile</id>
              <phase>compile</phase>
              <goals>
                <goal>compile</goal>
              </goals>
              <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <encoding>UTF-8</encoding>
              </configuration>
            </execution>
            <execution>
              <id>default-testCompile</id>
              <phase>test-compile</phase>
              <goals>
                <goal>testCompile</goal>
              </goals>
              <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <encoding>UTF-8</encoding>
              </configuration>
            </execution>
          </executions>
          <configuration>
            <source>1.8</source>
            <target>1.8</target>
            <encoding>UTF-8</encoding>
          </configuration>
        </plugin>

任何帮助将不胜感激!

【问题讨论】:

  • 您使用的 Spark 版本是使用 Scala 2.12 或更高版本编译的吗?在 Scala 2.12 中,特征直接编译为 Java 接口。这是因为 Java 8 在接口中引入了默认实现,因此 Scala 2.12(需要 Java 8+)可以转换为接口,而无需您链接到的答案中引用的复杂机制。我不是 Java 互操作专家,但如果确实存在 mkString 的默认实现,Java 应该会看到它。
  • 好吧,不幸的是我使用的是 spark 2.2。所以 2.12 不是一个选项......升级 spark 将完全超出我的任务范围,所以我现在必须忍受这个限制。但很高兴知道,谢谢!

标签: java scala apache-spark-sql maven-compiler-plugin


【解决方案1】:

我正在将我的评论添加到答案中,以便您可以将此问题标记为已回答。

TL;DR:如果 Scala 特征是由 2.12 之前的 Scala 版本编译的,则不能在 Java 中对 Scala 特征使用默认实现。此处使用的 Spark 版本就是这种情况,因此失去了所有希望。

原因与 Scala 编译器如何对特征进行编码以与 JVM(因此与 Java)兼容。

在 Java 8 之前,接口不允许提供默认实现。 Scala trait 基本上是具有默认实现的可堆叠接口,必须进行编码,既要有一个没有实现的接口,又要有一个提供实现的抽象类。详情请见this answer

在 Java 8 之后,接口被允许提供默认实现,因此 Scala 可以将具有默认实现的特征直接编码为 Java 接口,并直接与 Java 代码兼容。从 Scala 2.12 开始,Scala 需要兼容 Java 8+ 的 JVM,因此带来了 traitinterface 兼容性。如果 Scala 代码已由 Scala 2.12+ 编译器编译,则可以将其特征用作普通 Java 接口。

【讨论】:

    猜你喜欢
    • 2019-03-19
    • 1970-01-01
    • 1970-01-01
    • 2020-03-15
    • 1970-01-01
    • 1970-01-01
    • 2016-09-16
    • 1970-01-01
    • 2014-10-01
    相关资源
    最近更新 更多