假设这个简单的特征。暴露 val x 的特征。由于 x 的初始化成本非常高,我选择 val x = ... 而不是 def x = ...
trait ScalaTrait {
self =>
val x: Int = SomeVeryExpensiveOperation.do()
}
现在,如何实现这个特性的Java类。我当然不得不在我的Java类中使用公共方法实现 val x 。但是这里有一个问题:因为公共方法和我的特征的 val x 共享相同的名称,我不能只委托给特征实现:
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类必须首先实现 private val 字段?
答案 0 :(得分:3)
你真的不想这样做。您将不得不深入了解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
),setter方法(X$_setter_$x_
),并在构造函数中调用X$class.$init$