scala教程之:可見性規則

和java很相似,scala也有本身的可見性規則,不一樣的是scala只有private和protected關鍵字,沒有public關鍵字,同時scala還提供了更加細粒度的訪問控制如protected[scope]和private[scope]。java

public

scala中默認的訪問權限就是public,這意味着在scala中沒有可見性關鍵字的聲明體,他的訪問權限就是public,是具備公有可見性的。這與Java不一樣,Java 語言中默認的「公有」可見性只對包可見(即包內私有)。this

咱們看一個例子:scala

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和它的內部類Nested的字段是公有能夠訪問的。code

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 包內的對象不可見。作用域

private

私有(private)可見性將實現細節徹底隱藏起來,即使是繼承類的實現者也沒法訪問這些細節。聲明中包含了private 關鍵字的全部成員都只對定義該成員的類型可見,該類型的其餘實例也能訪問這些成員。get

注意,雖然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還提供了範圍內的可見性: scoped private 和 scoped protected。 scala的範圍有this,package和具體的某個類型。

簡單點講範圍內的可見性就是在範圍內保持該可見性的特性。

咱們能夠比較一下上面咱們在講private和proteced可見性的時候,二者在範圍內(class,package)的表現是同樣的,是能夠替換的,只有在繼承方面有差別。

咱們先看一下繼承的差別性:

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內部知足private/protected條件時候才能訪問,這樣就提供了更加細粒度的控制。

其中this scope是最嚴格的可見性,它代表可見性限制的字段只能在當前的scope或者type範圍以內。

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], 由於其是特定類型範圍內,因此equalFields方法會編譯錯誤,其沒法被其餘實例所訪問。

除此以外,使用private[this] 修飾的類成員的可見性與未指定做用域範圍的private 可見性一致。

再看一下包範圍內的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 做用域內,所以你沒法在scopeA2 做用域外聲明其子類。

同理,在與scopeA2無關的scopeB 做用域內使用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
}

如今咱們沒法在scopeA2 做用域外將PrivateClass2 子類化。不過因爲PrivateClass3 被聲明爲private[ScopeA] 類型,所以咱們能夠在scopeA 做用域內能將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 中訪問成員變量時,便會出現錯誤。

更多教程請參考 flydean的博客

相關文章
相關標籤/搜索