和java很相似,scala也有本身的可见性规则,不一样的是scala只有private和protected关键字,没有public关键字,同时scala还提供了更加细粒度的访问控制如protected[scope]和private[scope]。java
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 关键字声明的成员只对该定义类型可见,包括
相同类型的其余实例以及全部的继承类型。对象
咱们看一个例子:继承
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 关键字的全部成员都只对定义该成员的类型可见,该类型的其余实例也能访问这些成员。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 方法能够访问其余实例中定义的私有成员。
除了普通的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的博客