问题 Java类中的Scala getter和setter


我想创建一个遵循Scala setters / getters约定的Java类。

我试过跟随简单的类,但它不起作用:

public class JavaA {
private int a = 0;

public int a() {
    return a;
}

public void a_$eq(int a) {
    this.a = a;
}
}

但是当我尝试从scala访问它时:

val x = new JavaA
x.a = 1

我得到“重新分配给val”错误消息。我试图寻找这个,但是我发现从scala到java的另一个问题。

这样做的正确方法是什么?

谢谢!


7729
2018-06-05 12:28


起源

我正在使用EMF(model2model,model2text转换)工作很多,所以我想我会使用feature = value而不是setFeatute(value)来使代码更优雅。 - fikovnik


答案:


你只能这样做,而你可能不想这样做很难。

你是什​​么 不能 do是编写一个神奇的Java类,它被神奇地解释为Scala getter和setter。原因是Scala将信息嵌入到其getter和setter所需的类文件中(例如,没有参数块或一个空参数块 - 这种区别在JVM(或Java)中没有保留)。

你是什​​么 能够 do是使用Java来实现Scala定义的接口(即trait):

// GetSetA.scala
trait GetSetA { def a: Int; def a_=(a: Int): Unit }

// JavaUsesGSA.java
public class JavaUsesGSA implements GetSetA {
  private int a = 0;
  public int a() { return a; }
  public void a_$eq(int a) { this.a = a; }
}

你是什​​么 不能 即使这样,也直接使用该类(再次因为Java没有为Scala添加适当的注释信息):

scala> j.a = 5
<console>:8: error: reassignment to val
       j.a = 5

但既然如此  成功实现了特征,当你输入特征时可以根据需要使用它:

scala> (j: GetSetA).a = 5
(j: GetSetA).a: Int = 5

所以这是一个混合包。通过任何方式都不完美,但在某些情况下可能有足够的功能来帮助。

(另一种选择当然是提供从Java类到具有引用Java类的实际方法的getter / setter的隐式转换;即使您不能从Scala继承Java,这也是有效的。)

(编辑:当然没有关键的原因,编译器 必须 这样做;有人可能会认为将Java定义的getter / setter对解释为Scala类(即如果类文件没有明确地说它来自Scala),那么它就是改进Java互操作性的一个很好的候选者。)


13
2018-06-05 14:19



感谢您的见解!我担心它不起作用。 - fikovnik
尼斯;实施特质的酷炫技巧! - Jean-Philippe Pellet


我怕你不能。在Scala中,访问器必须是没有参数列表的方法,比如 def a = _a。写作例如 def a() = _a 在Scala中会导致相同的错误,并且您无法在Java中定义没有参数列表的方法。您可以通过生成自己的Scala编译器来欺骗它 ScalaSignature,但这可能不值得麻烦......


1
2018-06-05 14:00



但问题不在于访问者。 println(x.a) 工作得很好(就像 x.a_=(1))。 - Travis Brown
@TravisBrown这是因为语法糖仅在有这样的访问器时才有效,符合语言规范。 - Jean-Philippe Pellet
啊!你是对的。有多奇怪 - Travis Brown
scala示例并不完全正确,因为我记得, def a() = _a没有定义一个空的Parameterlist,而是一个需要Unit的。不确定这只是内部还是在编译过程中存活,但我猜它确实存在。 - kutschkem
@kutschkem你错了。 def a() = … 定义一个空参数列表。 - Jean-Philippe Pellet