Scala编程指南:面向对象编程

来源:java认证发布时间:2012-11-12 13:13:03java认证视频

    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

上一页234下一页

视频学习

我考网版权与免责声明

① 凡本网注明稿件来源为"原创"的所有文字、图片和音视频稿件,版权均属本网所有。任何媒体、网站或个人转载、链接转贴或以其他方式复制发表时必须注明"稿件来源:我考网",违者本网将依法追究责任;

② 本网部分稿件来源于网络,任何单位或个人认为我考网发布的内容可能涉嫌侵犯其合法权益,应该及时向我考网书面反馈,并提供身份证明、权属证明及详细侵权情况证明,我考网在收到上述法律文件后,将会尽快移除被控侵权内容。

最近更新

社区交流

考试问答