scala 为什么`private val` 和`private final val` 不同?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13412386/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why are `private val` and `private final val` different?
提问by Yang Bo
I used to think that private valand private final valare same, until I saw section 4.1 in Scala Reference:
我曾经认为private val和private final val是一样的,直到我在 Scala Reference 中看到第 4.1 节:
A constant value definition is of the form
final val x = ewhere e is a constant expression (§6.24). The final modifier must be present and no type annotation may be given. References to the constant value x are themselves treated as constant expressions; in the generated code they are replaced by the definition's right-hand side e.
常量值定义的形式为
final val x = e其中 e 是一个常量表达式(第 6.24 节)。final 修饰符必须存在,并且不能给出类型注释。对常量值 x 的引用本身被视为常量表达式;在生成的代码中,它们被定义的右侧 e 替换。
And I have written a test:
我写了一个测试:
class PrivateVal {
private val privateVal = 0
def testPrivateVal = privateVal
private final val privateFinalVal = 1
def testPrivateFinalVal = privateFinalVal
}
javap -coutput:
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
}
The byte code is just as Scala Reference said: private valis not private final val.
字节码正如 Scala Reference 所说:private val不是private final val。
Why doesn't scalacjust treat private valas private final val? Is there any underlying reason?
为什么scalac不只是private val当作private final val?有什么根本原因吗?
采纳答案by Steve Waldman
So, this is just a guess, but it was a perennial annoyance in Java that final static variables with a literal on the right-hand side get inlined into bytecode as constants. That engenders a performance benefit sure, but it causes binary compatibility of the definition to break if the "constant" ever changed. When defining a final static variable whose value might need to change, Java programmers have to resort to hacks like initializing the value with a method or constructor.
所以,这只是一个猜测,但在 Java 中,最终的静态变量在右侧带有文字,作为常量被内联到字节码中,这是一个长期的烦恼。这肯定会产生性能优势,但如果“常量”发生变化,则会导致定义的二进制兼容性中断。在定义其值可能需要更改的最终静态变量时,Java 程序员必须求助于诸如使用方法或构造函数初始化值之类的技巧。
A val in Scala is already final in the Java sense. It looks like Scala's designers are using the redundant modifier final to mean "permission to inline the constant value". So Scala programmers have complete control over this behavior without resorting to hacks: if they want an inlined constant, a value that should never change but is fast, they write "final val". if they want flexibility to change the value without breaking binary compatibility, just "val".
Scala 中的 val 在 Java 意义上已经是 final 了。看起来 Scala 的设计者正在使用冗余修饰符 final 来表示“允许内联常量值”。因此,Scala 程序员可以完全控制这种行为,而无需求助于黑客:如果他们想要一个内联常量,一个永远不会改变但速度很快的值,他们会编写“final val”。如果他们想要在不破坏二进制兼容性的情况下灵活地更改值,只需“val”。
回答by Connor Doyle
I think the confusion here arises from conflating immutability with the semantics of final. vals can be overridden in child classes and therefore can't be treated as final unless marked as such explicitly.
我认为这里的混淆源于将不变性与 final 的语义混为一谈。 vals 可以在子类中被覆盖,因此不能被视为最终的,除非明确标记为这样。
@Brian The REPL provides class scope at the line level. See:
@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

