简体   繁体   English

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

[英]Traits: Interop between Scala and Java, accessing val from Java

Assume this simple trait. 假设这个简单的特征。 A trait which exposes a val x . 暴露val x的特征 Since the initialization costs of x are very high I choose val x =... over def x =... 由于x的初始化成本非常高,我选择val x = ... over def x = ...

trait ScalaTrait {

  self =>

  val x: Int = SomeVeryExpensiveOperation.do()

}

Now how about a Java class implementing this trait. 现在如何实现这个特性的Java类。 I'm of course obliged to implement val x using a public method in my Java class. 我当然不得不在我的Java类中使用公共方法实现val x But here is the catch: because the public method and my trait's val x share the same name I can't just delegate to the trait implementation: 但是这里有一个问题:因为公共方法和我的特征的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!
    }

}

My question is what exactly should go inside method x()? 我的问题是究竟应该在方法x()内部进行什么?

As an alternative I could provide a public def accessor to that private val x field. 作为替代方案,我可以为该私有val x字段提供公共def访问器。 Like so: 像这样:

trait ScalaTrait {

  self =>

  private val _x: Int = SomeVeryExpensiveOperation.do()
  def x = _x

}

But still, I'm now forced to implement that private val _x in my Java class, too, regardless of the private access modifier. 但是,我现在也被迫在我的Java类中实现私有val _x ,而不管私有访问修饰符。 How can I make this work and why must my Java class implement the private val field in the first place? 我怎样才能完成这项工作?为什么我的Java类必须首先实现私有val字段?

You don't really want to do this. 你真的不想这样做。 You're going to have to dive into the guts of how Scala implements mixins and reimplement it by hand in Java. 您将不得不深入了解Scala如何实现mixins并在Java中手动重新实现它。

Here is a simple example, all in Scala: 这是一个简单的例子,全部在Scala中:

trait X {
  val x = 5
}

class Y extends X

We can use scalac -Xprint:mixin to get an intermediate stage in the Scala compilation process that shows what Scala does to implement Y : 我们可以使用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);
      ()
    }
  }
}

All that stuff for Y you are going to have to implement by hand in Java. Y所有东西你将不得不用Java手工实现。 You need to define the field ( x ), the accessor method (also x ), the setter method ( X$_setter_$x_ ), and put the call to X$class.$init$ in your constructor. 您需要定义字段( x ),访问器方法(也是x ),setter方法( X$_setter_$x_ ),并在构造函数中调用X$class.$init$

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM