美文网首页ScalaScala 在简书程序员
[5] - 类和对象之进阶(一)

[5] - 类和对象之进阶(一)

作者: 牛肉圆粉不加葱 | 来源:发表于2016-05-28 06:59 被阅读220次

    继承

    只能有一个父类

    与其他支持面向对象的语言一样,Scala 也支持继承,并且子类只能有一个父类,不能继承于多个父类,如果希望实现类似继承多个父类的功能,应该考虑引入 trait。虽然只支持一个父类,但是父类还可以有父类,也就是爷爷类,对于类继承的层数是没有具体要求的,这几点在下面这个例子中都有体现:

    scala> class A {
         | }
    defined class A
    
    scala> class B {
         | }
    defined class B
    
    scala> class AA extends A {
         | }
    defined class AA
    
    scala> class AB extends A with B {
         | }
    <console>:9: error: class B needs to be a trait to be mixed in
           class AB extends A with B {
                                   ^
    
    scala> class AAA extends AA {
         | }
    defined class AAA
    
    scala> class AAAA extends AAA {
         | }
    defined class AAAA
    

    都继承了什么

    子类继承父类时都会继承些什么呢,这里结合可见性(可见性的详细内容会在下文介绍)进行分析,先定义这样一组父子类:

    scala> class Parent ( x: Int, y: String, z: Double ) {
         |   val xx = x
         |   protected val yy = y
         |   private val zz = z
         |
         |   def getXX = xx
         |   protected def getYY = yy
         |   private def getZZ = zz
         |
         |   def testYY = yy
         |   def testZZ = zz
         |   def testGetYY = getYY
         |   def testGetZZ = getZZ
         | }
    defined class Parent
    

    在 Scala 类继承中,允许在子类内部直接访问父类的 public 及 protected 成员及方法,但不允许子类直接访问父类的 private 成员及方法,如下例:

    scala> class Child1 ( x: Int, y: String, z: Double ) extends Parent(x, y, z ) {
         |   println( xx )
         |   println( yy )
         |   println( getXX )
         |   println( getYY )
         | }
    defined class Child1
    
    scala> class Child2 ( x: Int, y: String, z: Double ) extends Parent(x, y, z ) {
         |   println( zz )
         |   println( getZZ )
         | }
    <console>:9: error: value zz in class Parent cannot be accessed in Child2
             println( zz )
                      ^
    <console>:10: error: method getZZ in class Parent cannot be accessed in Child2
             println( getZZ )
                      ^
    

    在类外部,只有 public 的方法和成员能被直接访问,protected 及 private 均不予许:

    scala> class Child3 ( x: Int, y: String, z: Double ) extends Parent(x, y, z ) {
         | }
    defined class Child3
    
    scala> val child = new Child3( 1, "hello", 3.1415926 )
    child: Child3 = Child3@39529185
    
    scala> child.xx
    res6: Int = 1
    
    scala> child.yy
    <console>:11: error: value yy in class Parent cannot be accessed in Child3
     Access to protected value yy not permitted because
     enclosing object $iw is not a subclass of
     class Parent where target is defined
                  child.yy
                        ^
    
    scala> child.zz
    <console>:11: error: value zz in class Parent cannot be accessed in Child3
                  child.zz
                        ^
    
    scala>
    
    scala> child.getXX
    res9: Int = 1
    
    scala> child.getYY
    <console>:11: error: method getYY in class Parent cannot be accessed in Child3
     Access to protected method getYY not permitted because
     enclosing object $iw is not a subclass of
     class Parent where target is defined
                  child.getYY
                        ^
    
    scala> child.getZZ
    <console>:11: error: method getZZ in class Parent cannot be accessed in Child3
                  child.getZZ
                        ^
    

    但我们可以通过父类提供的方法来间接访问 protected 和 private 的成员和方法:

    scala> child.testYY
    res20: String = hello
    
    scala> child.testZZ
    res21: Double = 3.1415926
    
    scala> child.testGetYY
    res22: String = hello
    
    scala> child.testGetZZ
    res23: Double = 3.1415926
    

    单例对象

    在 Scala 中,使用关键字 object 来定义单例对象:

    scala> object T {}
    defined module T
    

    单例对象将在其首次被调用时初始化,且没有参数。单例对象一旦定义完毕,它的名字就代表了该单例对象的唯一实例。

    当单例对象与某个类的名字相同且两者定义在同一文件中,就形成了特殊的单例对象-伴生对象,对应的类称为伴生类,若单例没有相同名字的类的话成为孤立对象(好惨)。我们经常使用在伴生对象中对应 apply 方法来创建新的伴生类实例并且将半身列的可见性设置为 private,以便能方便的创建伴生类实例,更重要的是可以在伴生类对象中管理所有伴生类实例,例子如下:

    class Q ( qParam: String ) {
      private val q = qParam
    }
    
    object Q {
      private val qList = ListBuffer[ Q ]()
    
      def apply( qParam: String ) {
        val qInstance = new Q( qParam )
        qList.append( qInstance )
        qInstance
      }
    
      def qListSize = qList.size
    }
    
    object Test {
      def main (args: Array[String]) {
        val qIns1 = Q( "q1" )
        val qIns2 = Q( "q2" )
        println( Q.qListSize )
      }
    }
    

    输出:

    2
    

    另外伴生对象与伴生类可以互相访问 private 成员和方法,object 也可以继承父类或混入特质。


    **传送门: **Scala 在简书目录


    欢迎关注我的微信公众号:FunnyBigData

    FunnyBigData

    相关文章

      网友评论

        本文标题:[5] - 类和对象之进阶(一)

        本文链接:https://www.haomeiwen.com/subject/prufdttx.html