I would like to create a Java class that follows the Scala setters/getters convention.
我想创建一个遵循Scala setter /getters约定的Java类。
I tried following simple class, but it does not work:
我试着按照简单的类,但它不起作用:
public class JavaA {
private int a = 0;
public int a() {
return a;
}
public void a_$eq(int a) {
this.a = a;
}
}
But when I try to access it from scala:
但是当我尝试从scala访问它时:
val x = new JavaA
x.a = 1
and I get "reassignment to val" error message. I tried to look for this, but all issues I found where the other way around from scala to java.
我得到了“重新分配给val”错误信息。我试着去寻找它,但是我发现的所有问题都是从scala到java的其他方面。
What is the right way to do it?
正确的做法是什么?
Thanks!
谢谢!
2 个解决方案
#1
13
You can only sort of do this, and it's hard enough that you probably don't want to.
你只能这么做,这很困难,你可能不想这么做。
What you can't do is write a bare Java class that magically is interpreted as Scala getters and setters. The reason is that Scala embeds information into the class file that it requires for its getters and setters (e.g. are there zero parameter blocks or one empty parameter block--a distinction which is not preserved on the JVM (or in Java)).
您不能做的是编写一个Java类,它神奇地解释为Scala getter和setter。原因是Scala将信息嵌入到它的getter和setter所需的类文件中(例如,是否有0个参数块或一个空参数块——JVM(或Java)上没有保留的区别)。
What you can do is use Java to implement a Scala-defined interface (i.e. trait):
您可以使用Java实现一个由标量定义的接口(即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; }
}
What you can't do, even so, is use the class directly (again because Java does not add the appropriate annotation information for Scala):
即使这样,您也不能直接使用该类(同样因为Java没有为Scala添加适当的注释信息):
scala> j.a = 5
<console>:8: error: reassignment to val
j.a = 5
but since it does implement the trait successfully, you can use it as desired when it is typed as the trait:
但是由于它确实成功地实现了这个特性,所以当它被类型化为这个特性时,您可以根据需要使用它:
scala> (j: GetSetA).a = 5
(j: GetSetA).a: Int = 5
So it's rather a mixed bag. Not perfect by any means, but it may be sufficiently functional to help out in some cases.
所以这是一个很复杂的包。无论如何都不完美,但在某些情况下,它可能有足够的功能来帮助解决问题。
(The other alternative, of course, is to provide an implicit conversion from the Java class to one that has a getter/setter that references the real methods on the Java class; this works even when you can't have the Java inherit from Scala.)
(当然,另一种选择是提供从Java类到具有引用Java类的实际方法的getter/setter的隐式转换;即使您无法从Scala继承Java,它也能工作。
(Edit: Of course there's no critical reason that the compiler must act this way; one could argue that interpreting Java-defined getter/setter pairs as if they were Scala ones (i.e. if the classfile does not explicitly say it's from Scala) is a good candidate for a feature enhancement to improve Java interoperability.)
(编辑:当然,没有重要的原因,编译器必须这样做;有人可能会说,将Java定义的getter/setter对解释为Scala的getter/setter对(例如,如果classfile没有明确地说它来自Scala)是改进Java互操作性的特性的一个很好的候选者。
#2
1
I’m afraid you can’t. In Scala, the accessor has to be method with no parameter list, like def a = _a
. Writing e.g. def a() = _a
in Scala would cause the same error, and there is no way that you can define a method with no parameter list in Java. You may be able to fool the Scala compiler by generating your own ScalaSignature
, but that's probably not worth the trouble…
恐怕你不能。在Scala中,访问器必须是没有参数列表的方法,比如def a = _a。在Scala中编写def a() = _a将导致相同的错误,并且您不可能在Java中定义一个没有参数列表的方法。您可以通过生成自己的Scala签名来骗过Scala编译器,但这可能不值得麻烦……
#1
13
You can only sort of do this, and it's hard enough that you probably don't want to.
你只能这么做,这很困难,你可能不想这么做。
What you can't do is write a bare Java class that magically is interpreted as Scala getters and setters. The reason is that Scala embeds information into the class file that it requires for its getters and setters (e.g. are there zero parameter blocks or one empty parameter block--a distinction which is not preserved on the JVM (or in Java)).
您不能做的是编写一个Java类,它神奇地解释为Scala getter和setter。原因是Scala将信息嵌入到它的getter和setter所需的类文件中(例如,是否有0个参数块或一个空参数块——JVM(或Java)上没有保留的区别)。
What you can do is use Java to implement a Scala-defined interface (i.e. trait):
您可以使用Java实现一个由标量定义的接口(即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; }
}
What you can't do, even so, is use the class directly (again because Java does not add the appropriate annotation information for Scala):
即使这样,您也不能直接使用该类(同样因为Java没有为Scala添加适当的注释信息):
scala> j.a = 5
<console>:8: error: reassignment to val
j.a = 5
but since it does implement the trait successfully, you can use it as desired when it is typed as the trait:
但是由于它确实成功地实现了这个特性,所以当它被类型化为这个特性时,您可以根据需要使用它:
scala> (j: GetSetA).a = 5
(j: GetSetA).a: Int = 5
So it's rather a mixed bag. Not perfect by any means, but it may be sufficiently functional to help out in some cases.
所以这是一个很复杂的包。无论如何都不完美,但在某些情况下,它可能有足够的功能来帮助解决问题。
(The other alternative, of course, is to provide an implicit conversion from the Java class to one that has a getter/setter that references the real methods on the Java class; this works even when you can't have the Java inherit from Scala.)
(当然,另一种选择是提供从Java类到具有引用Java类的实际方法的getter/setter的隐式转换;即使您无法从Scala继承Java,它也能工作。
(Edit: Of course there's no critical reason that the compiler must act this way; one could argue that interpreting Java-defined getter/setter pairs as if they were Scala ones (i.e. if the classfile does not explicitly say it's from Scala) is a good candidate for a feature enhancement to improve Java interoperability.)
(编辑:当然,没有重要的原因,编译器必须这样做;有人可能会说,将Java定义的getter/setter对解释为Scala的getter/setter对(例如,如果classfile没有明确地说它来自Scala)是改进Java互操作性的特性的一个很好的候选者。
#2
1
I’m afraid you can’t. In Scala, the accessor has to be method with no parameter list, like def a = _a
. Writing e.g. def a() = _a
in Scala would cause the same error, and there is no way that you can define a method with no parameter list in Java. You may be able to fool the Scala compiler by generating your own ScalaSignature
, but that's probably not worth the trouble…
恐怕你不能。在Scala中,访问器必须是没有参数列表的方法,比如def a = _a。在Scala中编写def a() = _a将导致相同的错误,并且您不可能在Java中定义一个没有参数列表的方法。您可以通过生成自己的Scala签名来骗过Scala编译器,但这可能不值得麻烦……