Private 可见性
Private 可见性完全隐藏了实现的细节,即使对于继承类的实现也一样。任何用private 关键字声明的成员只对定义它的类型可见,包括它的实例。当应用于类型时,private 限制其可见性为包含它的package。
// code-examples/BasicOOP/scoping/private-wont-compile.scala // WON'T COMPILE 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 } 编译这个文件会产生如下输出。
14: error: not found: value privateField1 val field1 = privateField1 ^ 15: error: not found: value privateField2 val field2 = privateField2 ^ 16: error: value nestedField cannot be accessed in PrivateClass2.this.Nested val nField = new Nested()。nestedField ^ 20: error: value privateField1 cannot be accessed in scopeA.PrivateClass1 val privateField1 = privateClass1.privateField1 ^ 21: error: value privateField2 cannot be accessed in scopeA.PrivateClass1 val privateField2 = privateClass1.privateField2 ^ 22: error: value nested cannot be accessed in scopeA.PrivateClass1 val privateNField = privateClass1.nested.nestedField ^ 27: error: private class PrivateClass4 escapes its defining scope as part of type scopeA.PrivateClass4 class PrivateClass5 extends PrivateClass4 ^ 28: error: private class PrivateClass4 escapes its defining scope as part of type scopeA.PrivateClass4 protected class PrivateClass6 extends PrivateClass4 ^ 33: error: class PrivateClass4 cannot be accessed in package scopeA class PrivateClass4B extends scopeA.PrivateClass4 ^ 9 errors found 现在,PrivateClass2 不能访问它的父类PrivateClass1 的private 成员。正如错误消息指出的,它们对于子类来说完全不可见。它们也不能存取嵌套类的private 字段。
正如protected 访问的例子一样,PrivateClass3 不能访问它使用的PrivateClass1 实例的private 成员。不过注意,equalFields 方法可以访问其它实例的private 成员。
PrivateClass5 和PrivateClass6 的声明失败了,因为如果允许的话,它们等于允许PrivateClass4 “跳出它的定义域”。然而,PrivateClass7 的声明成功了,因为它同时被定义为了private。令人好奇的是,我们上一个例子中能够正确地定义一个继承自protected 类的public 类。
最后,和protected 类型声明一样,private 类型不能在包含它的package 之外被继承。
局部 Private 和Protected 可见性
Scala 允许你用scoped private 和protected 可见性声明来更精细地调整可见性的范围。注意,在局部声明中使用proviate 或者protected 是可互换的,因为它们除了应用到继承的成员上的可见性之外,其它都是一样的。
提示
虽然在大多数情况下选择任何一个都能活动相同的效果,在代码中使用private 还是比protected 更常见一些。在Scala 的核心库里,这个比利大概是5:1。
让我们从scoped private 和scoped protected 之间的唯一区别入手,来看看当成员有这些局部性声明的时候,它们在继承机制下是如何工作的。
// code-examples/BasicOOP/scoping/scope-inheritance-wont-compile.scala // WON'T COMPILE 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 } } 编译这个文件会产生如下输出。
17: error: not found: value class1_privateField val field3 = class1_privateField // ERROR ^ 19: error: not found: value this_privateField val field5 = this_privateField // ERROR ^ 26: error: not found: value scopeA_privateField val field1 = scopeA_privateField // ERROR ^ 28: error: not found: value class1_privateField val field3 = class1_privateField // ERROR ^ 30: error: not found: value this_privateField val field5 = this_privateField // ERROR ^ 5 errors found Class2 里的前两个错误说明,在同一个package 内的继承类,不能引用父类或者this 的scoped private 成员,但是它可以引用包含Class1 和Class2 的package (或者类型)的private 成员。
相比之下,对于package 之外的继承类,它无法访问Class1 的任何一个scoped private 成员。
然而,所有的scoped protected 成员对于两个继承类来说都是可以见的。
我们会在后面剩下的例子和讨论中使用scoped private 声明,因为在Scala 库中,scoped private 比scoped protected 更加常见一些,前面的继承情况并不是其中一个因素。
首先,让我们从最严格的可见性开始,private[this],它也对类型成员起作用。
// code-examples/BasicOOP/scoping/private-this-wont-compile.scala // WON'T COMPILE 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) && (nested == other.nested) 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 } } 编译这个文件会产生如下输出。
5: error: value privateField1 is not a member of scopeA.PrivateClass1 (privateField1 == other.privateField1) && ^ 14: error: not found: value privateField1 val field1 = privateField1 ^ 15: error: not found: value privateField2 val field2 = privateField2 ^ 16: error: value nestedField is not a member of PrivateClass2.this.Nested val nField = new Nested()。nestedField ^ 20: error: value privateField1 is not a member of scopeA.PrivateClass1 val privateField1 = privateClass1.privateField1 ^ 21: error: value privateField2 is not a member of scopeA.PrivateClass1 val privateField2 = privateClass1.privateField2 ^ 22: error: value nested is not a member of scopeA.PrivateClass1 val privateNField = privateClass1.nested.nestedField ^ 7 errors found 注意
第6 到8 行无法解析。因为它们是第5 行开始的表达式的一部分,编译器在遇到第一个错误之后就会停住。
这些private[this] 成员仅对同一个实例内的成员可见。同一个类的不同实例之间无法访问对方的private[this] 成员,所以equalFields 方法无法通过解析。
否则,类成员的可见性就和没有域限定符的private 一样了。
当用private[this] 声明一个类型时,this 的使用被有效的绑定到了包含它的package 里,正如这里所展示的。
// code-examples/BasicOOP/scoping/private-this-pkg-wont-compile.scala // WON'T COMPILE package scopeA { private[this] class PrivateClass1 package scopeA2 { private[this] class PrivateClass2 } class PrivateClass3 extends PrivateClass1 // ERROR protected class PrivateClass4 extends PrivateClass1 // ERROR private class PrivateClass5 extends PrivateClass1 private[this] class PrivateClass6 extends PrivateClass1 private[this] class PrivateClass7 extends scopeA2.PrivateClass2 // ERROR } package scopeB { class PrivateClass1B extends scopeA.PrivateClass1 // ERROR } 编译这个文件会产生如下输出。
8: error: private class PrivateClass1 escapes its defining scope as part of type scopeA.PrivateClass1 class PrivateClass3 extends PrivateClass1 ^ 9: error: private class PrivateClass1 escapes its defining scope as part of type scopeA.PrivateClass1 protected class PrivateClass4 extends PrivateClass1 ^ 13: error: type PrivateClass2 is not a member of package scopeA.scopeA2 private[this] class PrivateClass7 extends scopeA2.PrivateClass2 ^ 17: error: type PrivateClass1 is not a member of package scopeA class PrivateClass1B extends scopeA.PrivateClass1 ^ four errors found 在同一个package 中,尝试声明一个public 或者protected 子类会失败。只有private 和private[this] 子类是允许的。而且,PrivateClass2 在scopeA2 里,所以你不能在scopeA2 之外声明它。简单地尝试在无关的scopeB 中声明一个使用PrivateClass1 的类也失败了。
因此,当应用到类型时,private[this] 和Java 的package private 可见性一致。
下面,让我们来检查类型级别的可见性,private[T],T 是一个类型。
// code-examples/BasicOOP/scoping/private-type-wont-compile.scala // WON'T COMPILE 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 nestednestedNested = 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 } } 编译这个文件会产生如下输出。
12: error: value nestedField cannot be accessed in PrivateClass1.this.Nested val nestednestedNested = nested.nestedField ^ 15: error: not found: value privateField1 val field1 = privateField1 ^ 16: error: not found: value privateField2 val field2 = privateField2 ^ 17: error: value nestedField cannot be accessed in PrivateClass2.this.Nested val nField = new Nested()。nestedField ^ 21: error: value privateField1 cannot be accessed in scopeA.PrivateClass1 val privateField1 = privateClass1.privateField1 ^ 22: error: value privateField2 cannot be accessed in scopeA.PrivateClass1 val privateField2 = privateClass1.privateField2 ^ 23: error: value nested cannot be accessed in scopeA.PrivateClass1 val privateNField = privateClass1.nested.nestedField ^ 7 errors found 一个private[PrivateClass1] 的成员对于其它实例来说也可见,所以equalFields 方法可以通过编译。因此,private[T] 不如private[this] 来得严格。注意,PrivateClass1 不能访问Nested.nestedField,因为那个字段被声明为private[Nested]。
提示
当T 的成员被声明为private[T] 的时候,其行为等同于private。但是它不同于private[this],后者更加严格。
如果我们修改Nested.nestedField 的范围,变成private[PrivateClass1] 会发生什么呢?让我们来看看private[T] 如何影响嵌套的类型。
// code-examples/BasicOOP/scoping/private-type-nested-wont-compile.scala // WON'T COMPILE package scopeA { class PrivateClass1 { class Nested { private[PrivateClass1] val nestedField = 1 } private[PrivateClass1] val nested = new Nested val nestednestedNested = nested.nestedField } class PrivateClass2 extends PrivateClass1 { val nField = new Nested()。nestedField // ERROR } class PrivateClass3 { val privateClass1 = new PrivateClass1 val privateNField = privateClass1.nested.nestedField // ERROR } } 编译这个文件会获得如下输出。
10: error: value nestedField cannot be accessed in PrivateClass2.this.Nested def nField = new Nested()。nestedField ^ 14: error: value nested cannot be accessed in scopeA.PrivateClass1 val privateNField = privateClass1.nested.nestedField ^ two errors found 现在nestedField 对PrivateClass1 来说可见,但是它对于PrivateClass1 之外来说仍然不可见。这就是private 在Java 中的工作。
让我们来用一个package 名字检查其作用范围。
// code-examples/BasicOOP/scoping/private-pkg-type-wont-compile.scala // WON'T COMPILE 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 } 编译这个文件会产生如下输出。
14: error: class PrivateClass2 cannot be accessed in package scopeA.scopeA2 private[this] class PrivateClass8 extends scopeA2.PrivateClass2 ^ 19: error: class PrivateClass1 cannot be accessed in package scopeA class PrivateClass1B extends scopeA.PrivateClass1 ^ two errors found 注意PrivateClass2 无法在scopeA2 之外被继承,但是PrivateClass3 可以在scopeA 中被继承,因为它被声明为private[ScopeA]。
最后,让我们来看一下package 级别的类型成员作用域效果。
// code-examples/BasicOOP/scoping/private-pkg-wont-compile.scala // WON'T COMPILE package scopeA { class PrivateClass1 { private[scopeA] val privateField = 1 class Nested { private[scopeA] val nestedField = 1 } private[scopeA] val nested = new Nested } class PrivateClass2 extends PrivateClass1 { val field = privateField val nField = new Nested()。nestedField } class PrivateClass3 { val privateClass1 = new PrivateClass1 val privateField = privateClass1.privateField val privateNField = privateClass1.nested.nestedField } package scopeA2 { class PrivateClass4 { private[scopeA2] val field1 = 1 private[scopeA] val field2 = 2 } } class PrivateClass5 { val privateClass4 = new scopeA2.PrivateClass4 val field1 = privateClass4.field1 // ERROR val field2 = privateClass4.field2 } } package scopeB { class PrivateClass1B extends scopeA.PrivateClass1 { val field1 = privateField // ERROR val privateClass1 = new scopeA.PrivateClass1 val field2 = privateClass1.privateField // ERROR } } 编译这个文件会获得如下输出。
28: error: value field1 cannot be accessed in scopeA.scopeA2.PrivateClass4 val field1 = privateClass4.field1 ^ 35: error: not found: value privateField val field1 = privateField ^ 37: error: value privateField cannot be accessed in scopeA.PrivateClass1 val field2 = privateClass1.privateField ^ three errors found 唯一的错误是尝试从无关的package scopeB 访问scopeA 的成员,或者尝试访问属于嵌套的package scopeA2 的成员。
提示
当一个类型或成员被声明为private[P],P是一个包含它们的package, 那么这就等同于Java 的package private 可见性。
对于可见性的总结
Scala 可见性声明非常灵活,并且行为准则一致。它们为所有可能的作用域提供了细致的可见性控制,从实例级别(private[this])到package 级别(private[P])。例如,它们使得创建在顶层package 之外暴露类型的组件更加容易,而且很好得在组件package 内部隐藏了类型和类型成员的实现。
最后,我们观察到了一个潜在trait 隐藏成员的“问题”。
编辑特别推荐:
Java读取文件内容再编辑
JS获取单选与多选按纽的值
每一种文件类型所对应的ContentType
① 凡本网注明稿件来源为"原创"的所有文字、图片和音视频稿件,版权均属本网所有。任何媒体、网站或个人转载、链接转贴或以其他方式复制发表时必须注明"稿件来源:我考网",违者本网将依法追究责任;
② 本网部分稿件来源于网络,任何单位或个人认为我考网发布的内容可能涉嫌侵犯其合法权益,应该及时向我考网书面反馈,并提供身份证明、权属证明及详细侵权情况证明,我考网在收到上述法律文件后,将会尽快移除被控侵权内容。