11

我想创建一个遵循 Scala 设置器/获取器约定的 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 的所有问题。

正确的方法是什么?

谢谢!

4

2 回答 2

13

你只能做到这一点,而且你可能不想这样做已经够难了。

不能做的是编写一个神奇地被解释为 Scala getter 和 setter 的裸 Java 类。原因是 Scala 将信息嵌入到它的 getter 和 setter 所需的类文件中(例如,是否有零参数块或一个空参数块——JVM(或 Java)中没有保留的区别)。

可以做的是使用 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

但由于它确实成功地实现了 trait,所以当它被输入为 trait 时,您可以根据需要使用它:

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

所以它是一个混合包。无论如何都不完美,但在某些情况下它可能具有足够的功能来提供帮助。

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

(编辑:当然,编译器必须以这种方式运行并没有关键的理由;有人可能会争辩说,将 Java 定义的 getter/setter 对解释为就好像它们是 Scala 的一样(即,如果类文件没有明确说明它来自 Scala)是一种改进 Java 互操作性的功能增强的良好候选者。)

于 2012-06-05T14:19:41.457 回答
1

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

于 2012-06-05T14:00:29.830 回答