[英]Scala Java interoperability with val
In scala, if we have a class say, 在斯卡拉,如果我们有一个班级说,
case class B(b: Int)
object B {
def main(args: Array[String] {
val b = B(1)
b.b = 2 // ** compile time error here **
}
}
would give an error saying, when compile with scalac B.scala
使用scalac B.scala
编译时会给出错误scalac B.scala
error: reassignment to val
b.b = 2
^
Everything is fine till here. 一切都很好,直到这里。
However, if I have a java class A.java
: 但是,如果我有一个Java类A.java
:
public class A {
public int a;
public A(int a) {this.a = a;}
public void setA(int a_) {this.a = a_;}
public String toString() {return "A: " + a;}
}
first compile it with javac A.java
, then use it in scala with val
: 首先使用javac A.java
进行javac A.java
,然后在val
中的scala中使用它:
object B {
def main(args: Array[String] {
val a = new A(1)
println("Before assignment: " + a)
a.a = 2 // ** No error here **
println("After assignment: " + a)
}
}
compile B.scala
with scalac B.scala
and run with scala B
. 使用scalac B.scala
编译B.scala
并使用scala B
运行。 No error occurs. 没有错误发生。
Does it break intention of val
in scala? 它是否破坏了scala中val
意图?
If I want to, when using java class in scala, maintain the fixed value of instance a
, what can I do? 如果我想在Scala中使用Java类时,保持实例a
的固定值,该怎么办?
Or there actually is some documentation mentioning this behavior? 还是实际上有一些文档提到此行为?
Environment: Scala version 2.11.5 (OpenJDK 64-Bit Server VM, Java 1.7.0_75).
Centos 6.6
Edit 编辑
Thank you everyone for your reply. 谢谢大家的答复。
While I am well aware that by making the field final: public final int a;
虽然我很清楚通过将字段定为final: public final int a;
, immutability can be achieved. ,可以实现不变性。
I'm not hoping to solve this problem by modifying java code. 我不希望通过修改Java代码来解决此问题。 Imagine that I'm using third party java libraries that I can no way modify their code, yet I want making sure my code won't accidentally modify third-party's internal state, hence come the val
. 想象一下,我正在使用第三方Java库,无法修改它们的代码,但是我想确保我的代码不会意外地修改第三方的内部状态,因此使用val
。
In addition, by disassembling the .class
file using javap -c
, it can be seen clearly that scala is not making Bb
immutable by inserting final
to class B
. 此外,通过使用javap -c
分解.class
文件,可以清楚地看到,通过将final
插入class B
,scala不会使Bb
成为不可变的。
Or maybe someone explaining the "magic" behind val
would be helpful 也许有人解释val
背后的“魔术”会有所帮助
Clearly in your Java class A
, the member a
is both public and mutable. 显然,在Java类A
,成员a
既是公共的又是可变的。 To treat a Java variable as Scala val
, you can make it final
in your Java class. 要将Java变量视为Scala val
,可以使其在Java类中final
。
Also remember that Scala too has var
which has essentially same behaviour as Java variables ( except for final
ones ). 还请记住,Scala也具有var
,它的行为与Java变量基本相同( final
变量除外)。
EDIT 1 编辑1
Define B
like so: 像这样定义B
:
case class B(val b: Int, var c: Int)
And then check the compiled class definition 然后检查编译后的类定义
$ javap B
Compiled from "B.scala"
public class B implements scala.Product,scala.Serializable {
public static scala.Option<scala.Tuple2<java.lang.Object, java.lang.Object>> unapply(B);
public static B apply(int, int);
public static void main(java.lang.String[]);
public int b();
public int c();
public int copy$default$1();
public int copy$default$2();
public void c_$eq(int);
public B copy(int, int);
public java.lang.String productPrefix();
public int productArity();
public java.lang.Object productElement(int);
public scala.collection.Iterator<java.lang.Object> productIterator();
public boolean canEqual(java.lang.Object);
public int hashCode();
public java.lang.String toString();
public boolean equals(java.lang.Object);
public B(int, int);
}
Thing to note here is that for member 'c' you will have public void c_$eq(int);
这里要注意的是,对于成员'c',您将有public void c_$eq(int);
but for member b
there is no such method. 但是对于成员b
,没有这种方法。 In fact in Scala, the assignment turns out to be a method call. 实际上,在Scala中,分配实际上是方法调用。
I hope that makes it clearer. 我希望这一点更加清楚。
Your confusion comes from line val a = new A(1)
in object B
. 您的困惑来自object B
行val a = new A(1)
。 It means that you cannot reassign value to your variable a
but it's completely ok to reassign any field of a
. 这意味着你不能重新分配价值,你的变量a
,但它是完全可以重新分配的任何领域的a
。 This can be limited by marking a filed be final 这可以通过将文件标记为最终文件来限制
Try making public int a
final
in your java class as following 尝试如下将public int a
您的java类中public int a
final
public class A {
public final int a;
public A(int a) {this.a = a;}
//public void setA(int a_) {this.a = a_;} //Compilation error here. Cannot assign to a final field
public String toString() {return "A: " + a;}
}
It will enforce that field a
of class A
cannot be reassigned. 它将强制不能重新分配类A
字段a
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.