Scala构造函数中的最终变量

Jef*_*rey 5 constructor scala final

我仍然是Scala的新手,但我知道你可以定义在构造函数中初始化的类变量

class AClass(aVal: String)
Run Code Online (Sandbox Code Playgroud)

这就像在java中执行以下操作

class AClass {
    private String aVal;

    public AClass(String aVal) {
        this.aVal = aVal;
    }
}
Run Code Online (Sandbox Code Playgroud)

在Java中,我会声明aVal为final.有没有办法在Scala语法中使aVal变量最终?

编辑:这是我在编译以下Scala类时所看到的:

class AClass(aVal: String) {
  def printVal() {
    println(aVal)
  }
}
Run Code Online (Sandbox Code Playgroud)

我跑了javap -private,得到了输出

public class AClass extends java.lang.Object implements scala.ScalaObject{
  private final java.lang.String aVal;
  public void printVal();
  public AClass(java.lang.String);
}
Run Code Online (Sandbox Code Playgroud)

当我更改scala类定义以class AClass(**val** aVal: String)获得以下输出时javap -private

public class AClass extends java.lang.Object implements scala.ScalaObject{
  private final java.lang.String aVal;
  public java.lang.String aVal();
  public void printVal();
  public AClass(java.lang.String);
}
Run Code Online (Sandbox Code Playgroud)

aVal生成公共方法.我还在这里学习 - 有人可以解释为什么会产生这种情况吗?

注意我使用的是scala 2.9

kin*_*ori 10

class AClass(aVal: String)
Run Code Online (Sandbox Code Playgroud)

在此代码中,aVal是最终变量.所以你已经有了一个最终变量.

class AClass(val aVal: String)
Run Code Online (Sandbox Code Playgroud)

在这段代码中,aVal是最终的,你有aVAl的getter.所以你可以像下面这样使用它

scala> val a= new AClass("aa")
a: A1 = A1@1d7d58f

scala> a.aVal
res2: String = aa
Run Code Online (Sandbox Code Playgroud)

最后,

class AClass(var aVal: String)
Run Code Online (Sandbox Code Playgroud)

在这段代码中,aVal不是final,你有aVal的getter和setter.所以你可以像下面这样使用它

scala> val a= new AClass("aa")
a: AClass = AClass@1c059f6

scala> a.aVal
res3: String = aa

scala> a.aVal = "bb"
a.aVal: String = bb

scala> a.aVal
res4: String = bb
Run Code Online (Sandbox Code Playgroud)


ret*_*nym 8

复制自我的回答:Scala final vs val用于并发可见性

这个术语有两个含义final:a)对于Scala字段/方法和Java方法,它意味着"不能在子类中覆盖"和b)对于Java字段和JVM字节码,它意味着"字段必须在构造函数中初始化,并且不能重新分配".

标有val(或等效地,没有修饰符的case类参数)的类参数在第二种意义上确实是最终的,因此是线程安全的.

这是证据:

scala>  class A(val a: Any); class B(final val b: Any); class C(var c: Any)
defined class A
defined class B
defined class C

scala> import java.lang.reflect._
import java.lang.reflect._

scala> def isFinal(cls: Class[_], fieldName: String) = {
     |   val f = cls.getDeclaredFields.find(_.getName == fieldName).get
     |   val mods = f.getModifiers
     |   Modifier.isFinal(mods)
     | }
isFinal: (cls: Class[_], fieldName: String)Boolean

scala> isFinal(classOf[A], "a")
res32: Boolean = true

scala> isFinal(classOf[B], "b")
res33: Boolean = true

scala> isFinal(classOf[C], "c")
res34: Boolean = false
Run Code Online (Sandbox Code Playgroud)

或者javap,可以从REPL方便地运行:

scala> class A(val a: Any)
defined class A

scala> :javap -private A
Compiled from "<console>"
public class A extends java.lang.Object implements scala.ScalaObject{
    private final java.lang.Object a;
    public java.lang.Object a();
    public A(java.lang.Object);
}
Run Code Online (Sandbox Code Playgroud)

如果非案例类的类参数未标记为valvar,并且未从任何方法引用它,则只需对该类的构造函数可见.然后,Scala编译器可以自由地优化远离字节码的字段.在Scala 2.9.1中,这似乎有效:

scala> class A(a: Any)
defined class A

scala> :javap -private A
Compiled from "<console>"
public class A extends java.lang.Object implements scala.ScalaObject{
    public A(java.lang.Object);
}
Run Code Online (Sandbox Code Playgroud)