在Java中使用Scala特性和实现的方法

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (20)

我想这是不可能调用从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

提问于
用户回答回答于

从Java角度来看Trait.scala编译成Trait 接口。因此,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

它转化为:

Trait1

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";
  }
}

Trait2

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";
  }
}

FooOnSteroids

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);
  }      
}

所以整个堆栈调用如下所示:

  • 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的'酒吧'方法

结果是“Foo,Trait1,Trait2”。

结论

如果您已经设法阅读所有内容,那么对原始问题的回答是前四行。

用户回答回答于

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

trait Trait {
  def bar: Unit
}

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

扫码关注云+社区