[英]Scala Java interoperability with val
在斯卡拉,如果我们有一个班级说,
case class B(b: Int)
object B {
def main(args: Array[String] {
val b = B(1)
b.b = 2 // ** compile time error here **
}
}
使用scalac B.scala
编译时会给出错误scalac B.scala
error: reassignment to val
b.b = 2
^
一切都很好,直到这里。
但是,如果我有一个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;}
}
首先使用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)
}
}
使用scalac B.scala
编译B.scala
并使用scala B
运行。 没有错误发生。
它是否破坏了scala中val
意图?
如果我想在Scala中使用Java类时,保持实例a
的固定值,该怎么办?
还是实际上有一些文档提到此行为?
Environment: Scala version 2.11.5 (OpenJDK 64-Bit Server VM, Java 1.7.0_75).
Centos 6.6
编辑
谢谢大家的答复。
虽然我很清楚通过将字段定为final: public final int a;
,可以实现不变性。
我不希望通过修改Java代码来解决此问题。 想象一下,我正在使用第三方Java库,无法修改它们的代码,但是我想确保我的代码不会意外地修改第三方的内部状态,因此使用val
。
此外,通过使用javap -c
分解.class
文件,可以清楚地看到,通过将final
插入class B
,scala不会使Bb
成为不可变的。
也许有人解释val
背后的“魔术”会有所帮助
显然,在Java类A
,成员a
既是公共的又是可变的。 要将Java变量视为Scala val
,可以使其在Java类中final
。
还请记住,Scala也具有var
,它的行为与Java变量基本相同( final
变量除外)。
编辑1
像这样定义B
:
case class B(val b: Int, var c: Int)
然后检查编译后的类定义
$ 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);
}
这里要注意的是,对于成员'c',您将有public void c_$eq(int);
但是对于成员b
,没有这种方法。 实际上,在Scala中,分配实际上是方法调用。
我希望这一点更加清楚。
您的困惑来自object B
行val a = new A(1)
。 这意味着你不能重新分配价值,你的变量a
,但它是完全可以重新分配的任何领域的a
。 这可以通过将文件标记为最终文件来限制
尝试如下将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;}
}
它将强制不能重新分配类A
字段a
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.