62

我想不可能从 Java 调用在 Scala 特征中实现的方法,或者有没有办法?

假设我在 Scala 中有:

trait Trait {
  def bar = {}
}

在Java中,如果我将它用作

class Foo implements Trait {
}

Java抱怨说Trait is not abstract and does not override abstract method bar() in Trait

4

2 回答 2

135

回答

从 Java 的角度来看Trait.scala是编译成Trait interface的。因此Trait,在 Java 中实现被解释为实现一个接口——这使您的错误消息显而易见。简短的回答:你不能利用 Java 中的 trait 实现,因为这会在 Java 中启用多重继承(!)

它是如何在 Scala 中实现的?

长答案:那么它在 Scala 中是如何工作的?查看生成的字节码/类可以找到以下代码:

interface Trait {
    void bar();
}

abstract class Trait$class {
    public static void bar(Trait thiz) {/*trait implementation*/}
}

class Foo implements Trait {
    public void bar() {
        Trait$class.bar(this);  //works because `this` implements Trait
    }
}
  • Trait是一个接口
  • 抽象Trait$class(不要与 混淆Trait.class)类是透明创建的,从技术上讲,它实现Trait接口。但是它确实有一个static bar()Trait实例为参数的方法(有点this
  • Foo实现Trait接口
  • scalacTrait通过委托给自动实现方法Trait$class。这实质上意味着调用Trait$class.bar(this).

请注意,Trait$class它既不是 的成员Foo,也不会Foo扩展它。它只是通过传递来委托给它this

混合多种特征

继续题外话 Scala 是如何工作的……话虽这么说,很容易想象在下面混合多个特征是如何工作的:

trait Trait1 {def ping(){}};
trait Trait2 {def pong(){}};
class Foo extends Trait1 with Trait2

翻译为:

class Foo implements Trait1, Trait2 {
  public void ping() {
    Trait1$class.ping(this);    //works because `this` implements Trait1
  }

  public void pong() {
    Trait2$class.pong(this);    //works because `this` implements Trait2
  }
}

覆盖相同方法的多个特征

现在很容易想象如何混合多个特征来覆盖相同的方法:

trait Trait {def bar(){}};
trait Trait1 extends Trait {override def bar(){}};
trait Trait2 extends Trait {override def bar(){}};

再次Trait1Trait2成为接口扩展Trait。现在如果Trait2在定义时最后出现Foo

class Foo extends Trait1 with Trait2

你会得到:

class Foo implements Trait1, Trait2 {
    public void bar() {
        Trait2$class.bar(this); //works because `this` implements Trait2
    }
}

然而,切换Trait1Trait2Trait1最后)将导致:

class Foo implements Trait2, Trait1 {
    public void bar() {
        Trait1$class.bar(this); //works because `this` implements Trait1
    }
}

可堆叠的修改

现在考虑作为可堆叠修改的特征是如何工作的。想象一下有一个非常有用的类 Foo:

class Foo {
  def bar = "Foo"
}

您想使用特征来丰富一些新功能:

trait Trait1 extends Foo {
  abstract override def bar = super.bar + ", Trait1"
}

trait Trait2 extends Foo {
  abstract override def bar = super.bar + ", Trait2"
}

这是类固醇的新“Foo”:

class FooOnSteroids extends Foo with Trait1 with Trait2

它转化为:

特质1

interface Trait1 {
  String Trait1$$super$bar();
  String bar();
}
abstract class Trait1$class {
  public static String bar(Trait1 thiz) {
    // interface call Trait1$$super$bar() is possible
    // since FooOnSteroids implements Trait1 (see below)
    return thiz.Trait1$$super$bar() + ", Trait1";
  }
}

特质2

public interface Trait2 {
  String Trait2$$super$bar();
  String bar();
}
public abstract class Trait2$class {
  public static String bar(Trait2 thiz) {
    // interface call Trait2$$super$bar() is possible
    // since FooOnSteroids implements Trait2 (see below)
    return thiz.Trait2$$super$bar() + ", Trait2";
  }
}

FooOn类固醇

class FooOnSteroids extends Foo implements Trait1, Trait2 {
  public final String Trait1$$super$bar() {
    // call superclass 'bar' method version
    return Foo.bar();
  }

  public final String Trait2$$super$bar() {
    return Trait1$class.bar(this);
  }

  public String bar() {
    return Trait2$class.bar(this);
  }      
}

所以整个堆栈调用如下:

  • FooOnStroids 实例(入口点)上的“bar”方法;
  • Trait2$class 的 'bar' 静态方法将 this 作为参数传递并返回 'Trait2$$super$bar()' 方法调用和字符串 ", Trait2" 的串联;
  • FooOnSteroids 实例上的“Trait2$$super$bar()”调用...
  • Trait1$class 的 'bar' 静态方法将 this 作为参数传递并返回 'Trait1$$super$bar()' 方法调用和字符串 ", Trait1" 的串联;
  • FooOnSteroids 实例上的“Trait1$$super$bar”调用...
  • 原始 Foo 的 'bar' 方法

结果是“Foo,Trait1,Trait2”。

结论

如果您已设法阅读所有内容,则原始问题的答案在前四行中...

于 2011-10-03T16:32:58.280 回答
2

它确实不是抽象的,因为bar它返回一个空值Unit(一种 NOP)。尝试:

trait Trait {
  def bar: Unit
}

然后bar将是一个返回的 Java 抽象方法void

于 2011-10-03T16:33:03.780 回答