为什么“private val”和“private final val”不同?
我曾经认为, private val
和private final val
是相同的,直到我看到在斯卡拉参考4.1节:
恒定值的定义是这种forms
final val x = e
其中e是一个常数expression式(§6.24)。 最终修饰符必须存在,并且不能给出types注释。 常量值x的引用本身被视为常量expression式; 在生成的代码中,它们被定义的右边replacee。
我写了一个testing:
class PrivateVal { private val privateVal = 0 def testPrivateVal = privateVal private final val privateFinalVal = 1 def testPrivateFinalVal = privateFinalVal }
javap -c
输出:
Compiled from "PrivateVal.scala" public class PrivateVal { public int testPrivateVal(); Code: 0: aload_0 1: invokespecial #19 // Method privateVal:()I 4: ireturn public int testPrivateFinalVal(); Code: 0: iconst_1 1: ireturn public PrivateVal(); Code: 0: aload_0 1: invokespecial #24 // Method java/lang/Object."<init>":()V 4: aload_0 5: iconst_0 6: putfield #14 // Field privateVal:I 9: return }
字节码正如Scala Reference所说的: private val
不是private final val
。
为什么不把scalac视为private final val
? 有没有什么深层原因?
所以,这只是一个猜测,但是在Java中常常感到烦恼,最后一个静态variables在右边的字面量被作为常量内联到字节码中。 这确实会带来性能上的好处,但是如果“常量”发生了变化,则会导致定义的二进制兼容性被破坏。 当定义一个最终的静态variables的值可能需要改变时,Java程序员必须求助于像使用方法或构造函数初始化值的方法。
在Java中,Scala中的val已经是最终的了。 它看起来像斯卡拉的devise师使用冗余修饰符最后意思是“许可内联恒定值”。 因此,Scala程序员可以完全控制这种行为,而不必采取黑客行为:如果他们想要一个内联常量,一个永远不会改变但速度很快的值,他们会写“final val”。 如果他们想在不破坏二进制兼容性的情况下灵活地改变这个值,只需要“val”。
我认为这里的混乱是由于将不变性与最终语义混为一谈。 val
可以在子类中被覆盖,因此不能被视为最终的,除非明确标记。
@Brian REPL在行级提供类作用域。 看到:
scala> $iw.getClass.getPackage res0: Package = package $line3 scala> private val x = 5 <console>:5: error: value x cannot be accessed in object $iw lazy val $result = `x` scala> private val x = 5; println(x); 5