我仍然是Scala的新手,但我知道你可以定义在构造函数中初始化的类变量,如
class AClass(aVal: String)
就像在java中执行以下操作
class AClass {
private String aVal;
public AClass(String aVal) {
this.aVal = aVal;
}
}
在Java中,我会声明aVal为final。有没有办法在Scala语法中使aVal变量最终?
编辑:这是我在编译以下Scala类时所看到的:
class AClass(aVal: String) {
def printVal() {
println(aVal)
}
}
我跑了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);
}
当我将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);
}
生成公共方法aVal
。我还在这里学习 - 有谁可以解释为什么会产生这个?
注意我正在使用scala 2.9
答案 0 :(得分:10)
class AClass(aVal: String)
在此代码中,aVal是最终变量。所以你已经有了一个最终变量。
class AClass(val aVal: String)
在此代码中,aVal是最终的,你有aVAl的getter。所以你可以像下面那样使用它
scala> val a= new AClass("aa")
a: A1 = A1@1d7d58f
scala> a.aVal
res2: String = aa
最后,
class AClass(var aVal: String)
在这段代码中,aVal不是最终的,你有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
答案 1 :(得分:8)
从我的回答中复制:Scala final vs val for concurrency visibility
术语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
或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);
}
如果非案例类的class参数未标记为val
或var
,并且未从任何方法引用它,则只需要对其构造函数可见类。然后,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);
}