繁体   English   中英

Scala Java与Val的互操作性

[英]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 Bval 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM