简体   繁体   English

Scala Java与Val的互操作性

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

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