在Java中使用Scala特性和实现的方法
我想这是不可能调用从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的angular度来看, Trait.scala
被编译到Trait
界面 。 因此,在Java中实现Trait
被解释为实现一个接口 – 这使得你的错误信息变得明显。 简短的回答:你不能利用Java中的trait实现,因为这将启用Java中的多重inheritance(!)
它在Scala中如何实现?
长的答案:那么它在Scala中如何工作? 查看生成的字节码/类可以find以下代码:
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
混淆)类是透明创build的,在技术上不会实现Trait
接口。 然而,它确实有一个static bar()
方法以Trait
实例作为参数(sorting) -
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" }
你想用一些新的function来丰富你的特质:
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'静态方法将此参数作为parameter passing,并返回'Trait2 $$ super $ bar()'方法调用和string“Trait2”的串联。
- 'Trait2 $$ super $ bar()'在FooOnSteroids实例调用…
- Trait1 $ class的'bar'静态方法将此参数作为parameter passing,并返回'Trait1 $$ super $ bar()'方法调用和string“Trait1”的串联。
- 调用FooOnSteroids实例的'Trait1 $$ super $ bar'…
- 原来的Foo的“酒吧”方法
结果是“Foo,Trait1,Trait2”。
结论
如果你已经设法阅读所有的东西,最初的问题的答案是前四行
因为bar
正在返回一个空Unit
(一种NOP),所以确实不是抽象的。 尝试:
trait Trait { def bar: Unit }
然后bar
会是一个返回void
的Java抽象方法。