特点:Scala和Java之间的互操作,从Java访问val



假设这个简单的特性。公开值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$的调用放在构造函数中。

最新更新