2012-11-16 98 views
89

我曾經認爲private valprivate final val一樣,直到我Scala中參考用SAW 4.1節:爲什麼`private val`和`private final val`不同?

恆定值的定義是以下形式的

final val 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 valprivate final val

爲什麼沒有scalac只看待private valprivate final val?有沒有什麼深層原因?

+24

換句話說:由於'val'已經是不可變的,爲什麼我們在Scala中需要'final'關鍵字呢?爲什麼編譯器不能像'final val'一樣對待所有'val'? – Jesper

+0

請注意,'private'作用域修飾符與Java中的'package private'具有相同的語義。你可能會說'私人[this]'。 –

+3

@ConnorDoyle:作爲包私人?我不這麼認爲:'private'意味着它只對這個類的實例可見,'private [this]'只有這個實例 - 除了相同的類**的實例外,'private'不允許任何人(包括來自相同的包)來訪問該值。 – Make42

回答

75

所以,這只是一個猜測,但它是在Java中常年煩惱與在右側文字最終靜態變量得到內聯成字節碼爲常數。這確實會帶來性能上的好處,但是如果「常量」有變化,它會導致定義的二進制兼容性被破壞。當定義一個最終的靜態變量,其值可能需要改變時,Java程序員必須求助於像使用方法或構造函數初始化值的方法。

一個VAL在Scala是Java中的最後已。看起來Scala的設計師使用冗餘修飾符final來表示「允許內聯恆定值」。所以斯卡拉程序員不訴諸黑客對此行爲的完全控制權:如果他們想要一個內聯常數,即不應該改變,但速度快的值,就寫「最後的VAL」。如果他們想要在不破壞二進制兼容性的情況下靈活地更改該值,只需「val」即可。

+8

是的,這是對非私營丘壑的原因,但私人丘壑顯然不能在其他類內聯,打破以同樣的方式兼容。 –

+3

當我將'private val'更改爲'private final val'時,是否存在任何二進制兼容性問題? –

+1

@ steve-waldman對不起,你的意思是'val'在你的第二段? –

7

我認爲這裏的混亂產生與最終的語義混爲一談不變性。 val s可以在子類中重寫,因此不能被視爲最終的,除非明確標記。

@布賴恩的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 
+1

我說關於'私人val'。它可以被覆蓋嗎? –

+0

不,私人vals不能被覆蓋。您可以在子類中重新定義另一個具有相同名稱的私有val,但它是一個完全不同的val,只是恰好具有相同的名稱。 (老一個所有引用仍然會提到舊的。) – aij

+1

它似乎並不僅僅是這個壓倒一切的行爲,不過,因爲我可以在解釋作出最終VAL(甚至最終VAR)而不被一個班級的背景。 – Brian

相關問題