scala教程之:可见性规则
文章目錄
- public
- Protected
- private
- scoped private 和 scoped protected
和java很類似,scala也有自己的可見性規則,不同的是scala只有private和protected關鍵字,沒有public關鍵字,同時scala還提供了更加細粒度的訪問控制如protected[scope]和private[scope]。
public
scala中默認的訪問權限就是public,這意味著在scala中沒有可見性關鍵字的聲明體,他的訪問權限就是public,是具有公有可見性的。這與Java不同,Java 語言中默認的“公有”可見性只對包可見(即包內私有)。
我們看一個例子:
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的字段是公有可以訪問的。
Protected
所有使用protected 關鍵字聲明的成員只對該定義類型可見,包括
相同類型的其他實例以及所有的繼承類型。
我們看一個例子:
package scopeA {class ProtectedClass1(protected val protectedField1: Int) {protected val protectedField2 = 1def 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 = protectedField1val field2 = protectedField2val nField = new Nested().nestedField // ERROR}class ProtectedClass3 {val protectedClass1 = new ProtectedClass1(1)val protectedField1 = protectedClass1.protectedField1 // ERRORval protectedField2 = protectedClass1.protectedField2 // ERRORval protectedNField = protectedClass1.nested.nestedField // ERROR}protected class ProtectedClass4class ProtectedClass5 extends ProtectedClass4protected 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 關鍵字的所有成員都只對定義該成員的類型可見,該類型的其他實例也能訪問這些成員。
注意,雖然private的繼承者無法訪問成員,但是包含該字段的類型的其他實例也可以訪問這些成員。
舉個例子:
package scopeA {class PrivateClass1(private val privateField1: Int) {private val privateField2 = 1def 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 // ERRORval field2 = privateField2 // ERRORval nField = new Nested().nestedField // ERROR}class PrivateClass3 {val privateClass1 = new PrivateClass1(1)val privateField1 = privateClass1.privateField1 // ERRORval privateField2 = privateClass1.privateField2 // ERRORval privateNField = privateClass1.nested.nestedField // ERROR}private class PrivateClass4class PrivateClass5 extends PrivateClass4 // ERRORprotected class PrivateClass6 extends PrivateClass4 // ERRORprivate 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 = 1protected[scopeA] val scopeA_protectedField = 2private[Class1] val class1_privateField = 3protected[Class1] val class1_protectedField = 4private[this] val this_privateField = 5protected[this] val this_protectedField = 6}class Class2 extends Class1 {val field1 = scopeA_privateField val field2 = scopeA_protectedField val field3 = class1_privateField // ERRORval field4 = class1_protectedField val field5 = this_privateField // ERRORval field6 = this_protectedField } }package scopeB {class Class2B extends scopeA.Class1 {val field1 = scopeA_privateField // ERRORval field2 = scopeA_protectedField val field3 = class1_privateField // ERRORval field4 = class1_protectedField val field5 = this_privateField // ERRORval 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 = 1def equalFields(other: PrivateClass1) =(privateField1 == other.privateField1) &&(privateField2 == other.privateField2) &&(nested == other.nested)class Nested {private[Nested] val nestedField = 1}private[PrivateClass1] val nested = new Nestedval nestedNested = nested.nestedField // ERROR}class PrivateClass2 extends PrivateClass1(1) {val field1 = privateField1 // ERRORval field2 = privateField2 // ERRORval nField = new Nested().nestedField // ERROR}class PrivateClass3 {val privateClass1 = new PrivateClass1(1)val privateField1 = privateClass1.privateField1 // ERRORval privateField2 = privateClass1.privateField2 // ERRORval privateNField = privateClass1.nested.nestedField // ERROR} }由于可見性類型為private[PrivateClass1] 的成員對其他同類型實例可見, 因此equalFields 能夠通過解析。
我們再看看包級的可見性:
package scopeA {private[scopeA] class PrivateClass1package scopeA2 {private [scopeA2] class PrivateClass2private [scopeA] class PrivateClass3}class PrivateClass4 extends PrivateClass1protected class PrivateClass5 extends PrivateClass1private class PrivateClass6 extends PrivateClass1private[this] class PrivateClass7 extends PrivateClass1private[this] class PrivateClass8 extends scopeA2.PrivateClass2 // ERRORprivate[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 = 1def equalFields(other: PrivateClass1) =(privateField1 == other.privateField1) && // ERROR(privateField2 == other.privateField2) && // ERROR(nested == other.nested) // ERRORclass Nested {private[this] val nestedField = 1}private[this] val nested = new Nested}class PrivateClass2 extends PrivateClass1(1) {val field1 = privateField1 // ERRORval field2 = privateField2 // ERRORval nField = new Nested().nestedField // ERROR}class PrivateClass3 {val privateClass1 = new PrivateClass1(1)val privateField1 = privateClass1.privateField1 // ERRORval privateField2 = privateClass1.privateField2 // ERRORval privateNField = privateClass1.nested.nestedField // ERROR} }如果我們試圖從某個與scopeA 無關的包scopeB 中訪問scopeA 時,或者當我們嘗試從嵌套包scopeA2 中訪問成員變量時,便會出現錯誤。
更多精彩內容且看:
- 區塊鏈從入門到放棄系列教程-涵蓋密碼學,超級賬本,以太坊,Libra,比特幣等持續更新
- Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續更新
- Spring 5.X系列教程:滿足你對Spring5的一切想象-持續更新
- java程序員從小工到專家成神之路(2020版)-持續更新中,附詳細文章教程
更多教程請參考 flydean的博客
總結
以上是生活随笔為你收集整理的scala教程之:可见性规则的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Scala教程之:深入理解协变和逆变
- 下一篇: Spring MVC 中的http Ca