为什么`private val`和`private final val`是不同的?
为什么`private val`和`private final val`是不同的?
我曾经认为private val
和private final val
是一样的,直到我看到了《Scala参考》的第4.1节:\n
\n常量值定义的形式为\n
final val x = e\n其中e是一个常量表达式(§6.24)。必须有final修饰符,并且不能给出类型注解。对常量值x的引用本身被视为常量表达式;在生成的代码中,它们被定义的右侧e替换。\n
\n我写了一个测试:\n
class PrivateVal { private val privateVal = 0 def testPrivateVal = privateVal private final val privateFinalVal = 1 def testPrivateFinalVal = privateFinalVal }
\njavap -c
输出:\n
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."":()V 4: aload_0 5: iconst_0 6: putfield #14 // Field privateVal:I 9: return }
\n字节码正如《Scala参考》所说:private val
并不等同于private final val
。\n为什么scalac不把private val
当作private final val
来处理呢?是否有任何根本原因?
为什么`private val`和`private final val`不同?
混淆不可变性和final的语义是导致混淆的原因。`val`可以在子类中被重写,因此除非显式标记为final,否则不能被视为final。
REPL在行级别提供类作用域。参见以下示例:
scala> $iw.getClass.getPackage res0: Package = package $line3 scala> private val x = 5:5: error: value x cannot be accessed in object $iw lazy val $result = `x` scala> private val x = 5; println(x); 5
我在谈论`private val`。它可以被重写吗?
不,私有的val不能被重写。你可以在子类中重新定义另一个同名的私有val,但它只是一个完全不同的val,只是碰巧有相同的名称。(对旧val的所有引用仍然引用旧val)
然而,似乎不仅仅是重写行为,因为我可以在解释器中在没有类上下文的情况下创建一个final val(甚至是final var)。
问题的解决方法是使用`private final val`来确保val不能被子类重写。这样可以避免混淆,并确保代码的可预测性和可维护性。
在Java中,final static变量的右侧如果是一个字面值,会被内联为字节码常量。这样做确实会带来性能上的好处,但如果这个"常量"发生变化,就会导致定义的二进制兼容性被破坏。因此,在Java中,当定义的final static变量的值可能需要改变时,程序员必须采取一些hack的方法,比如使用方法或构造函数来初始化值。
在Scala中,val已经在Java的意义上是final的。Scala的设计者使用冗余修饰符final来表示"内联常量值的权限"。因此,Scala程序员可以完全控制这种行为,而无需使用hack的方法:如果他们希望有一个内联常量,即一个永远不会改变但是速度很快的值,他们写"final val"。如果他们希望在不破坏二进制兼容性的情况下更改值,只需写"val"即可。
是的,这是非私有val的原因,但是私有val显然无法在其他类中内联,并以相同的方式破坏兼容性。
将private val
更改为private final val
是否会产生任何二进制兼容性问题?
- Waldman 请问,你在第二段中的意思是val
吗?
关于Java中final static变量的二进制兼容性,可以参考这里的详细信息:docs.oracle.com/javase/specs/jls/se7/html/…