为什么“private val”和“private final val”不同?

我曾经认为, private valprivate 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