假设这个简单的特性。公开值x的trait。由于x的初始化成本非常高,我选择val x =… over def =…
trait ScalaTrait {
self =>
val x: Int = SomeVeryExpensiveOperation.do()
}
现在让Java类实现这个特性。当然,我必须使用Java类中的公共方法来实现val x。但这里有一个问题:因为公共方法和我的trait的val x共享相同的名称,我不能仅仅委托给trait实现:
class JavaClass imlements ScalaTrait {
@Override
public x() {
/* I can't hand over this call to x() of the trait,
since this would be a recursive call inside the Java class itself*/
return x(); <-- so, this no can do!
}
}
我的问题是到底应该去里面的方法x()?
作为一种替代方法,我可以为私有val x字段提供一个公共def访问器。像这样:
trait ScalaTrait {
self =>
private val _x: Int = SomeVeryExpensiveOperation.do()
def x = _x
}
但是,我现在仍然被迫在Java类中实现私有的val _x,而不管私有访问修饰符是什么。我怎样才能使它工作,为什么我的Java类必须首先实现私有val字段?
你不会真的想这么做。您将不得不深入了解Scala如何实现mixins,并在Java中手工重新实现它。
下面是一个简单的例子,全部用Scala编写:
trait X {
val x = 5
}
class Y extends X
我们可以使用scalac -Xprint:mixin
在Scala编译过程中获得一个中间阶段,显示Scala如何实现Y
:
[[syntax trees at end of mixin]] // test20.scala
package <empty> {
abstract trait X extends Object {
<accessor> def X$_setter_$x_=(x$1: Int): Unit;
<stable> <accessor> def x(): Int
};
class Y extends Object with X {
<stable> <accessor> def x(): Int = Y.this.x;
private[this] val x: Int = _;
<accessor> def X$_setter_$x_=(x$1: Int): Unit = Y.this.x = x$1;
def <init>(): Y = {
Y.super.<init>();
X$class./*X$class*/$init$(Y.this);
()
}
};
abstract trait X$class extends {
def /*X$class*/$init$($this: X): Unit = {
$this.X$_setter_$x_=(5);
()
}
}
}
所有的Y
的东西,你将不得不在Java中手工实现。您需要定义字段(x
)、访问方法(也是x
)、设置方法(X$_setter_$x_
),并将对X$class.$init$
的调用放在构造函数中。