scala教程之:可見性規(guī)則

和java很類似纵苛,scala也有自己的可見性規(guī)則,不同的是scala只有private和protected關鍵字催跪,沒有public關鍵字讥邻,同時scala還提供了更加細粒度的訪問控制如protected[scope]和private[scope]。

public

scala中默認的訪問權限就是public蜒什,這意味著在scala中沒有可見性關鍵字的聲明體测秸,他的訪問權限就是public,是具有公有可見性的灾常。這與Java不同霎冯,Java 語言中默認的“公有”可見性只對包可見(即包內(nèi)私有)。

我們看一個例子:

package scopeA {
class PublicClass1 {
val publicField = 1
class Nested {
val nestedField = 1
}
val nested = new Nested
}
class PublicClass2 extends PublicClass1 {
val field2 = publicField + 1
val nField2 = new Nested().nestedField
}
}
package scopeB {
class PublicClass1B extends scopeA.PublicClass1
class UsingClass(val publicClass: scopeA.PublicClass1) {
def method = "UsingClass:" +
" field: " + publicClass.publicField +
" nested field: " + publicClass.nested.nestedField
}
}

我們可以看到PublicClass1和它的內(nèi)部類Nested的字段是公有可以訪問的岗憋。

Protected

所有使用protected 關鍵字聲明的成員只對該定義類型可見肃晚,包括
相同類型的其他實例以及所有的繼承類型。

我們看一個例子:

package scopeA {
  class ProtectedClass1(protected val protectedField1: Int) {
    protected val protectedField2 = 1

    def equalFields(other: ProtectedClass1) =
      (protectedField1 == other.protectedField1) &&
      (protectedField2 == other.protectedField2) &&
      (nested == other.nested)


    class Nested {
      protected val nestedField = 1
    }

    protected val nested = new Nested
  }

  class ProtectedClass2 extends ProtectedClass1(1) {
    val field1 = protectedField1
    val field2 = protectedField2
    val nField = new Nested().nestedField  // ERROR
  }

  class ProtectedClass3 {
    val protectedClass1 = new ProtectedClass1(1)
    val protectedField1 = protectedClass1.protectedField1 // ERROR
    val protectedField2 = protectedClass1.protectedField2 // ERROR
    val protectedNField = protectedClass1.nested.nestedField // ERROR
  }

  protected class ProtectedClass4

  class ProtectedClass5 extends ProtectedClass4
  protected class ProtectedClass6 extends ProtectedClass4
}

package scopeB {
  class ProtectedClass4B extends scopeA.ProtectedClass4 // ERROR
}

由于ProtectedClass2 繼承了Protected1 類仔戈,因此ProtectedClass2 能訪問ProtectedClass1中定義的受保護成員关串。不過,ProtectedClass2 無法訪問protectedClass1.nested 對象中受保護的nestedField 成員监徘。同時晋修,ProtectedClass3 類也無法訪問它使用的ProtectedClass1實例中的受保護成員。

最后凰盔,由于ProtectedClass4 被聲明為protected 類墓卦,其對scopeB 包內(nèi)的對象不可見。

private

私有(private)可見性將實現(xiàn)細節(jié)完全隱藏起來户敬,即便是繼承類的實現(xiàn)者也無法訪問這些細節(jié)落剪。聲明中包含了private 關鍵字的所有成員都只對定義該成員的類型可見睁本,該類型的其他實例也能訪問這些成員。

注意忠怖,雖然private的繼承者無法訪問成員呢堰,但是包含該字段的類型的其他實例也可以訪問這些成員。

舉個例子:


package scopeA {
  class PrivateClass1(private val privateField1: Int) {
    private val privateField2 = 1

    def equalFields(other: PrivateClass1) =
      (privateField1 == other.privateField1) &&
      (privateField2 == other.privateField2) &&
      (nested == other.nested)

    class Nested {
      private val nestedField = 1
    }

    private val nested = new Nested
  }

  class PrivateClass2 extends PrivateClass1(1) {
    val field1 = privateField1  // ERROR
    val field2 = privateField2  // ERROR
    val nField = new Nested().nestedField // ERROR
  }

  class PrivateClass3 {
    val privateClass1 = new PrivateClass1(1)
    val privateField1 = privateClass1.privateField1 // ERROR
    val privateField2 = privateClass1.privateField2 // ERROR
    val privateNField = privateClass1.nested.nestedField // ERROR
  }

  private class PrivateClass4

  class PrivateClass5 extends PrivateClass4  // ERROR
  protected class PrivateClass6 extends PrivateClass4 // ERROR
  private class PrivateClass7 extends PrivateClass4
}

package scopeB {
  class PrivateClass4B extends scopeA.PrivateClass4  // ERROR
}

其他的都很好解釋凡泣, 請注意枉疼,equalFields 方法可以訪問其他實例中定義的私有成員

scoped private 和 scoped protected

除了普通的public鞋拟,private和protected這三種可見性外骂维,scala還提供了范圍內(nèi)的可見性: scoped private 和 scoped protected。 scala的范圍有this贺纲,package和具體的某個類型航闺。

簡單點講范圍內(nèi)的可見性就是在范圍內(nèi)保持該可見性的特性。

我們可以比較一下上面我們在講private和proteced可見性的時候哮笆,兩者在范圍內(nèi)(class来颤,package)的表現(xiàn)是一樣的汰扭,是可以替換的稠肘,只有在繼承方面有差異。

我們先看一下繼承的差異性:

package scopeA {
  class Class1 {
    private[scopeA]   val scopeA_privateField = 1
    protected[scopeA] val scopeA_protectedField = 2
    private[Class1]   val class1_privateField = 3
    protected[Class1] val class1_protectedField = 4
    private[this]     val this_privateField = 5
    protected[this]   val this_protectedField = 6
  }

  class Class2 extends Class1 {
    val field1 = scopeA_privateField    
    val field2 = scopeA_protectedField  
    val field3 = class1_privateField     // ERROR
    val field4 = class1_protectedField  
    val field5 = this_privateField       // ERROR
    val field6 = this_protectedField  
  }
}

package scopeB {
  class Class2B extends scopeA.Class1 {
    val field1 = scopeA_privateField     // ERROR
    val field2 = scopeA_protectedField  
    val field3 = class1_privateField     // ERROR
    val field4 = class1_protectedField  
    val field5 = this_privateField       // ERROR
    val field6 = this_protectedField  
  }
}

scope private/protected只能在該scope內(nèi)部滿足private/protected條件時候才能訪問萝毛,這樣就提供了更加細粒度的控制项阴。

其中this scope是最嚴格的可見性,它表明可見性限制的字段只能在當前的scope或者type范圍之內(nèi)笆包。

package scopeA {
class PrivateClass1(private[this] val privateField1: Int) {
private[this] val privateField2 = 1
def equalFields(other: PrivateClass1) =
(privateField1 == other.privateField1) && // 錯誤
(privateField2 == other.privateField2) && // 錯誤
(nested == other.nested) // 錯誤
class Nested {
private[this] val nestedField = 1
}
private[this] val nested = new Nested
}
class PrivateClass2 extends PrivateClass1(1) {
val field1 = privateField1 // 錯誤
val field2 = privateField2 // 錯誤
val nField = new Nested().nestedField // 錯誤
}
class PrivateClass3 {
val privateClass1 = new PrivateClass1(1)
val privateField1 = privateClass1.privateField1 // 錯誤
val privateField2 = privateClass1.privateField2 // 錯誤
val privateNField = privateClass1.nested.nestedField // 錯誤
}
}

我們先看一下類型范圍的private[this], 因為其是特定類型范圍內(nèi)环揽,所以equalFields方法會編譯錯誤,其無法被其他實例所訪問庵佣。

除此之外歉胶,使用private[this] 修飾的類成員的可見性與未指定作用域范圍的private 可見性一致。

再看一下包范圍內(nèi)的private[this] :

package scopeA {
private[this] class PrivateClass1
package scopeA2 {
private[this] class PrivateClass2
}
class PrivateClass3 extends PrivateClass1 // 錯誤
protected class PrivateClass4 extends PrivateClass1 // 錯誤
private class PrivateClass5 extends PrivateClass1
private[this] class PrivateClass6 extends PrivateClass1
private[this] class PrivateClass7 extends scopeA2.PrivateClass2 // 錯誤
}
package scopeB {
class PrivateClass1B extends scopeA.PrivateClass1 // 錯誤
}

在相同包中巴粪,無法成功地為一個private[this] 類型聲明public 或protected 子類通今,你只能為其聲明private 和private[this] 子類。與此同時肛根,由于PrivateClass2 的可見性被限定在scopeA2 作用域內(nèi)辫塌,因此你無法在scopeA2 作用域外聲明其子類。

同理派哲,在與scopeA2無關的scopeB 作用域內(nèi)使用PrivateClass1 聲明類同樣會失敗臼氨。

我們再看下private[T] 的可見性,其中T 代表了某一類型

package scopeA {
  class PrivateClass1(private[PrivateClass1] val privateField1: Int) {
    private[PrivateClass1] val privateField2 = 1

    def equalFields(other: PrivateClass1) =
      (privateField1 == other.privateField1) &&
      (privateField2 == other.privateField2) &&
      (nested  == other.nested)

    class Nested {
      private[Nested] val nestedField = 1
    }

    private[PrivateClass1] val nested = new Nested
    val nestedNested = nested.nestedField   // ERROR
  }

  class PrivateClass2 extends PrivateClass1(1) {
    val field1 = privateField1  // ERROR
    val field2 = privateField2  // ERROR
    val nField = new Nested().nestedField  // ERROR
  }

  class PrivateClass3 {
    val privateClass1 = new PrivateClass1(1)
    val privateField1 = privateClass1.privateField1  // ERROR
    val privateField2 = privateClass1.privateField2  // ERROR
    val privateNField = privateClass1.nested.nestedField // ERROR
  }
}

由于可見性類型為private[PrivateClass1] 的成員對其他同類型實例可見芭届, 因此equalFields 能夠通過解析储矩。

我們再看看包級的可見性:

package scopeA {
  private[scopeA] class PrivateClass1

  package scopeA2 {
    private [scopeA2] class PrivateClass2
    private [scopeA]  class PrivateClass3
  }

  class PrivateClass4 extends PrivateClass1
  protected class PrivateClass5 extends PrivateClass1
  private class PrivateClass6 extends PrivateClass1
  private[this] class PrivateClass7 extends PrivateClass1

  private[this] class PrivateClass8 extends scopeA2.PrivateClass2 // ERROR
  private[this] class PrivateClass9 extends scopeA2.PrivateClass3
}

package scopeB {
  class PrivateClass1B extends scopeA.PrivateClass1 // ERROR
}

現(xiàn)在我們無法在scopeA2 作用域外將PrivateClass2 子類化感耙。不過由于PrivateClass3 被聲明為private[ScopeA] 類型,因此我們可以在scopeA 作用域內(nèi)能將PrivateClass3 子類化持隧。

再看看放在類型里面的包級可見性:

package scopeA {
  class PrivateClass1(private[this] val privateField1: Int) {
    private[this] val privateField2 = 1

    def equalFields(other: PrivateClass1) =
      (privateField1 == other.privateField1) && // ERROR
      (privateField2 == other.privateField2) && // ERROR
      (nested == other.nested)   // ERROR

    class Nested {
      private[this] val nestedField = 1
    }

    private[this] val nested = new Nested
  }

  class PrivateClass2 extends PrivateClass1(1) {
    val field1 = privateField1  // ERROR
    val field2 = privateField2  // ERROR
    val nField = new Nested().nestedField  // ERROR
  }

  class PrivateClass3 {
    val privateClass1 = new PrivateClass1(1)
    val privateField1 = privateClass1.privateField1  // ERROR
    val privateField2 = privateClass1.privateField2  // ERROR
    val privateNField = privateClass1.nested.nestedField // ERROR
  }
}

如果我們試圖從某個與scopeA 無關的包scopeB 中訪問scopeA 時抑月,或者當我們嘗試從嵌套包scopeA2 中訪問成員變量時,便會出現(xiàn)錯誤舆蝴。

更多教程請參考 flydean的博客

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末谦絮,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子洁仗,更是在濱河造成了極大的恐慌层皱,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赠潦,死亡現(xiàn)場離奇詭異叫胖,居然都是意外死亡,警方通過查閱死者的電腦和手機她奥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門瓮增,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人哩俭,你說我怎么就攤上這事绷跑。” “怎么了凡资?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵砸捏,是天一觀的道長。 經(jīng)常有香客問我隙赁,道長垦藏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任伞访,我火速辦了婚禮掂骏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘厚掷。我一直安慰自己弟灼,他們只是感情好,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布蝗肪。 她就那樣靜靜地躺著袜爪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪薛闪。 梳的紋絲不亂的頭發(fā)上辛馆,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天,我揣著相機與錄音,去河邊找鬼昙篙。 笑死腊状,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的苔可。 我是一名探鬼主播缴挖,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼焚辅!你這毒婦竟也來了映屋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤同蜻,失蹤者是張志新(化名)和其女友劉穎棚点,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體湾蔓,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡瘫析,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了默责。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片聪富。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡艾恼,死狀恐怖常侣,靈堂內(nèi)的尸體忽然破棺而出溯职,到底是詐尸還是另有隱情,我是刑警寧澤葡缰,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布亏掀,位于F島的核電站,受9級特大地震影響泛释,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜温算,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一怜校、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧注竿,春花似錦茄茁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至宣谈,卻和暖如春愈犹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工漩怎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留勋颖,地道東北人。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓勋锤,卻偏偏與公主長得像饭玲,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子叁执,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容