我以前认为private val和private final val是一样的,直到我在Scala引用中看到了4.1节:
常量值定义的形式为 终值x=e 其中e是一个常量表达式(§6.24)。最后的修饰符必须存在,不能给出类型注释。对常量值x的引用本身被视为常量表达式;在生成的代码中,它们被定义的右侧e替换。
我写了一个测试:
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引用中所说的一样:private val不是private final val。
为什么scalac不把private val当作private final val呢?有什么根本的原因吗?
发布于 2012-11-16 08:27:22
因此,这只是猜测,但在Java中,最后的静态变量(右边有文字)作为常量被内联到字节码中,这是一个长期的烦恼。这肯定会带来性能上的好处,但如果“常量”发生变化,则会导致定义的二进制兼容性中断。当定义最后一个值可能需要更改的静态变量时,Java程序员不得不求助于黑客,比如用方法或构造函数初始化值。
Scala中的val在Java意义上已经是最终的了。看起来Scala的设计者使用冗余修饰符final来表示“允许内联常量值”。因此Scala程序员可以完全控制这种行为,而不必求助于黑客:如果他们想要一个内联的常量(这个值永远不会改变,但速度很快),他们就会编写"final“。如果他们希望在不破坏二进制兼容性的情况下灵活地更改值,只需使用"val“即可。
发布于 2012-11-17 06:38:43
我认为这里的混乱是由于将不可变性与最终语义学混为一谈。val可以在子类中被重写,因此,除非显式地标记为final,否则不能将其视为final。
@Brian在行级别提供类范围。请参见:
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);
5https://stackoverflow.com/questions/13412386
复制相似问题