将Scala特性与Java中实现的方法结合使用

将Scala特性与Java中实现的方法结合使用,java,scala,scala-java-interop,Java,Scala,Scala Java Interop,我想从Java调用Scala traits中实现的方法是不可能的,或者有办法吗 假设我在Scala中有: trait Trait { def bar = {} } 在Java中,如果我将其用作 class Foo implements Trait { } Java抱怨Trait不是抽象的,并且没有覆盖Trait中的抽象方法bar() 从Java的角度来看,Trait.scala被编译成Trait接口。因此,在Java中实现Trait被解释为实现了一个接口,这使得错误消息显而易见。简短回答

我想从Java调用Scala traits中实现的方法是不可能的,或者有办法吗

假设我在Scala中有:

trait Trait {
  def bar = {}
}
在Java中,如果我将其用作

class Foo implements Trait {
}
Java抱怨Trait不是抽象的,并且没有覆盖Trait中的抽象方法bar() 从Java的角度来看,
Trait.scala
被编译成
Trait
接口。因此,在Java中实现
Trait
被解释为实现了一个接口,这使得错误消息显而易见。简短回答:您不能利用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
    接口。但是,它确实有一个
    静态条()
    方法,该方法将
    Trait
    实例作为参数(类似于
    this
  • Foo
    实现
    Trait
    接口
  • scalac
    通过委托给
    Trait$class
    自动实现
    Trait
    方法。这本质上意味着调用
    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(){}};
同样地,
Trait1
Trait2
将成为扩展
Trait
的接口。现在,如果定义
Foo
Trait2
排在最后:

class Foo extends Trait1 with Trait2
您将获得:

class Foo implements Trait1, Trait2 {
    public void bar() {
        Trait2$class.bar(this); //works because `this` implements Trait2
    }
}
但是,切换
Trait1
Trait2
(将
Trait1
设为最后一个)将导致:

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

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

class Foo {
  def bar = "Foo"
}
您希望通过使用traits的一些新功能来丰富这些特性:

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
它的意思是:

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
  }
}
Trait1 Trait2 食物甾体 因此,整个堆栈调用如下所示:

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

结论
如果你已经阅读了所有内容,原始问题的答案就在前四行…

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


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

,这就是我的问题。如果我在
Trait
bar
中实现了一个复杂的方法,我希望在Java类中重用它,就像在Scala中一样。但我想这是不可能的。唯一的解决办法似乎是将Trait转换成一个抽象类。你应该把它变成一个抽象类。或者更好的做法是,将其作为一个特性,但添加一个抽象类,该类只是扩展了它(以具有Java绑定)。然后,您可以从Scala扩展trait,或者从Java继承抽象类。是的,尽管这将占用Java抽象类的唯一可用位置。其他解决方案是使用组合/聚合。您可以使用生成的静态方法(参见Tomasz答案)或者编写一个适合Java交互的对象。。。它缺少了
抽象覆盖的工作方式,但在其他方面它非常好。:-)谢谢还有一个输入错误:当你打算切换Trait1和Trait2时,你又写了一次
类Foo实现了Trait1,Trait2
。@KajMagnus:这部分是Tvaroh添加的,也许他可以修复它?@TomaszNurkiewicz抱歉我误读了答案。我认为这是正确的。(没有注意到相关的代码片段实际上是Java代码而不是Scala代码)。+1作为一名编译器开发人员(和爱好者),这些信息非常有用。现在我不需要自己进行反向工程。非常感谢这是一个错误吗?这句话不应该看起来像“Java抱怨Foo不是抽象的,并且没有覆盖Trait中的抽象方法bar()”吗?
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";
  }
}
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);
  }      
}
trait Trait {
  def bar: Unit
}