和java很類似,scala也有自己的可見性規(guī)則,不同的是scala只有private和protected關(guān)鍵字,沒有public關(guān)鍵字,同時(shí)scala還提供了更加細(xì)粒度的訪問控制如protected[scope]和private[scope]。
public
scala中默認(rèn)的訪問權(quán)限就是public,這意味著在scala中沒有可見性關(guān)鍵字的聲明體,他的訪問權(quán)限就是public,是具有公有可見性的。這與Java不同,Java 語言中默認(rèn)的“公有”可見性只對(duì)包可見(即包內(nèi)私有)。
我們看一個(gè)例子:
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 關(guān)鍵字聲明的成員只對(duì)該定義類型可見,包括
相同類型的其他實(shí)例以及所有的繼承類型。
我們看一個(gè)例子:
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中定義的受保護(hù)成員。不過,ProtectedClass2 無法訪問protectedClass1.nested 對(duì)象中受保護(hù)的nestedField 成員。同時(shí),ProtectedClass3 類也無法訪問它使用的ProtectedClass1實(shí)例中的受保護(hù)成員。
最后,由于ProtectedClass4 被聲明為protected 類,其對(duì)scopeB 包內(nèi)的對(duì)象不可見。
private
私有(private)可見性將實(shí)現(xiàn)細(xì)節(jié)完全隱藏起來,即便是繼承類的實(shí)現(xiàn)者也無法訪問這些細(xì)節(jié)。聲明中包含了private 關(guān)鍵字的所有成員都只對(duì)定義該成員的類型可見,該類型的其他實(shí)例也能訪問這些成員。
注意,雖然private的繼承者無法訪問成員,但是包含該字段的類型的其他實(shí)例也可以訪問這些成員。
舉個(gè)例子:
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
}
其他的都很好解釋, 請(qǐng)注意,equalFields 方法可以訪問其他實(shí)例中定義的私有成員。
scoped private 和 scoped protected
除了普通的public,private和protected這三種可見性外,scala還提供了范圍內(nèi)的可見性: scoped private 和 scoped protected。 scala的范圍有this,package和具體的某個(gè)類型。
簡單點(diǎn)講范圍內(nèi)的可見性就是在范圍內(nèi)保持該可見性的特性。
我們可以比較一下上面我們?cè)谥vprivate和proteced可見性的時(shí)候,兩者在范圍內(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條件時(shí)候才能訪問,這樣就提供了更加細(xì)粒度的控制。
其中this scope是最嚴(yán)格的可見性,它表明可見性限制的字段只能在當(dāng)前的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) && // 錯(cuò)誤
(privateField2 == other.privateField2) && // 錯(cuò)誤
(nested == other.nested) // 錯(cuò)誤
class Nested {
private[this] val nestedField = 1
}
private[this] val nested = new Nested
}
class PrivateClass2 extends PrivateClass1(1) {
val field1 = privateField1 // 錯(cuò)誤
val field2 = privateField2 // 錯(cuò)誤
val nField = new Nested().nestedField // 錯(cuò)誤
}
class PrivateClass3 {
val privateClass1 = new PrivateClass1(1)
val privateField1 = privateClass1.privateField1 // 錯(cuò)誤
val privateField2 = privateClass1.privateField2 // 錯(cuò)誤
val privateNField = privateClass1.nested.nestedField // 錯(cuò)誤
}
}
我們先看一下類型范圍的private[this], 因?yàn)槠涫翘囟愋头秶鷥?nèi),所以equalFields方法會(huì)編譯錯(cuò)誤,其無法被其他實(shí)例所訪問。
除此之外,使用private[this] 修飾的類成員的可見性與未指定作用域范圍的private 可見性一致。
再看一下包范圍內(nèi)的private[this] :
package scopeA {
private[this] class PrivateClass1
package scopeA2 {
private[this] class PrivateClass2
}
class PrivateClass3 extends PrivateClass1 // 錯(cuò)誤
protected class PrivateClass4 extends PrivateClass1 // 錯(cuò)誤
private class PrivateClass5 extends PrivateClass1
private[this] class PrivateClass6 extends PrivateClass1
private[this] class PrivateClass7 extends scopeA2.PrivateClass2 // 錯(cuò)誤
}
package scopeB {
class PrivateClass1B extends scopeA.PrivateClass1 // 錯(cuò)誤
}
在相同包中,無法成功地為一個(gè)private[this] 類型聲明public 或protected 子類,你只能為其聲明private 和private[this] 子類。與此同時(shí),由于PrivateClass2 的可見性被限定在scopeA2 作用域內(nèi),因此你無法在scopeA2 作用域外聲明其子類。
同理,在與scopeA2無關(guān)的scopeB 作用域內(nèi)使用PrivateClass1 聲明類同樣會(huì)失敗。
我們?cè)倏聪聀rivate[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] 的成員對(duì)其他同類型實(shí)例可見, 因此equalFields 能夠通過解析。
我們?cè)倏纯窗?jí)的可見性:
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 子類化。
再看看放在類型里面的包級(jí)可見性:
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
}
}
如果我們?cè)噲D從某個(gè)與scopeA 無關(guān)的包scopeB 中訪問scopeA 時(shí),或者當(dāng)我們嘗試從嵌套包scopeA2 中訪問成員變量時(shí),便會(huì)出現(xiàn)錯(cuò)誤。
更多教程請(qǐng)參考 flydean的博客