• 7、scala面向对象-继承


    一、继承

    1、extends

    Scala中,让子类继承父类,与Java一样,也是使用extends关键字 
    继承就代表,子类可以从父类继承父类的field和method;然后子类可以在自己内部放入父类所没有,
    子类特有的field和method;使用继承可以有效复用代码 
    子类可以覆盖父类的field和method;但是如果父类用final修饰,field和method用final修饰,则该类是无法被继承的,
    field和method是无法被覆盖的;
    
    
    ###
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Person {
      private var name = "leo"
      def getName = name
    }
    
    class Student extends Person {
     private var score  = "A"
     def getScore = score
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Person
    defined class Student
    warning: previously defined object Person is not a companion to class Person.
    Companions must be defined together; you may wish to use :paste mode for this.
    
    scala> val s = new Student
    s: Student = Student@985696
    
    scala> s.getName
    res11: String = leo
    
    scala> s.getScore
    res12: String = A
    
    scala> s.getName
    res13: String = leo
    
    scala> s.name
    <console>:14: error: value name is not a member of Student
           s.name
             ^


    2、override和super

    //Scala中,如果子类要覆盖一个父类中的非抽象方法,则必须使用override关键字;
    
    //override关键字可以帮助我们尽早地发现代码里的错误,比如:override修饰的父类方法的方法名我们拼写错了;比如要覆盖的父类方法的参数我们写错了;等等
    
    //此外,在子类覆盖父类方法之后,如果我们在子类中就是要调用父类的被覆盖的方法呢?
       那就可以使用super关键字,显式地指定要调用父类的方法
    
    
    ###
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Person {
      private var name = "leo"
      def getName = name
    }
    
    class Student extends Person {
      private var score = "A"
      def getScore = score
      override def getName = "Hi, I'm a student, my name is " + super.getName
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Person
    defined class Student
    warning: previously defined object Person is not a companion to class Person.
    Companions must be defined together; you may wish to use :paste mode for this.
    
    scala> val s = new Student
    s: Student = Student@618ad2aa
    
    scala> s.getName
    res15: String = Hi, I'm a student, my name is leo


    3、override field

    // Scala中,子类可以覆盖父类的val field,而且子类的val field还可以覆盖父类的val field的getter方法;只要在子类中使用override关键字即可
    
    ###
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Person {
      val name: String = "Person"
      def age: Int = 0
    }
    
    class Student extends Person { 
      override val name: String  = "leo"
      override val age: Int = 30
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Person
    defined class Student
    warning: previously defined object Person is not a companion to class Person.
    Companions must be defined together; you may wish to use :paste mode for this.
    
    scala> val p = new Person
    p: Person = Person@71d9cb05
    
    scala> p.name
    res16: String = Person
    
    scala> p.age
    res17: Int = 0
    
    scala> val s = new Student
    s: Student = Student@1ac4ccad
    
    scala> s.name
    res18: String = leo
    
    scala> s.age
    res19: Int = 30


    4、isInstanceOf和asInstanceOf

    // 如果我们创建了子类的对象,但是又将其赋予了父类类型的变量。则在后续的程序中,我们又需要将父类类型的变量转换为子类类型的变量,应该如何做?
    // 首先,需要使用isInstanceOf判断对象是否是指定类的对象,如果是的话,则可以使用asInstanceOf将对象转换为指定类型
    // 注意,如果对象是null,则isInstanceOf一定返回false,asInstanceOf一定返回null
    // 注意,如果没有用isInstanceOf先判断对象是否为指定类的实例,就直接用asInstanceOf转换,则可能会抛出异常
    
    
    
    ###
    scala> class Person
    defined class Person
    warning: previously defined object Person is not a companion to class Person.
    Companions must be defined together; you may wish to use :paste mode for this.
    
    scala> class Student extends Person
    defined class Student
    
    scala> val p: Person = new Student
    p: Person = Student@f324455
    
    scala> var s: Student = null
    s: Student = null
    
    scala> if (p.isInstanceOf[Student]) s = p.asInstanceOf[Student]


    5、getClass和classOf

    // isInstanceOf只能判断出对象是否是指定类以及其子类的对象,而不能精确判断出,对象就是指定类的对象
    // 如果要求精确地判断对象就是指定类的对象,那么就只能使用getClass和classOf了
    // 对象.getClass可以精确获取对象的类,classOf[类]可以精确获取类,然后使用==操作符即可判断
    
    
    ###
    scala> class Person
    defined class Person
    
    scala> class Student extends Person
    defined class Student
    
    scala> val p: Person = new Student
    p: Person = Student@77468bd9
    
    scala> p.isInstanceOf[Person]
    res0: Boolean = true
    
    scala> p.getClass == classOf[Person]
    res1: Boolean = false
    
    scala> p.getClass == classOf[Student]
    res2: Boolean = true


    6、使用模式匹配进行类型判断

    // 但是在实际开发中,比如spark的源码中,大量的地方都是使用了模式匹配的方式来进行类型的判断,这种方式更加地简洁明了,
    而且代码得可维护性和可扩展性也非常的高
    // 使用模式匹配,功能性上来说,与isInstanceOf一样,也是判断主要是该类以及该类的子类的对象即可,不是精准判断的
    
    
    
    ###
    scala> class Person
    defined class Person
    
    scala> class Student extends Person
    defined class Student
    
    scala> val p: Person = new Student
    p: Person = Student@192d3247
    
    scala> p match {
         |   case per: Person => println("it's Person's object")
         |   case _ => println("unknown type")
         | }
    it's Person's object


    7、protected

    // 跟java一样,scala中同样可以使用protected关键字来修饰field和method,这样在子类中就不需要super关键字,直接就可以访问field和method
    // 还可以使用protected[this],则只能在当前子类对象中访问父类的field和method,无法通过其他子类对象访问父类的field和method
    
    
    ###
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Person {
      protected var name: String = "leo"
    }
    
    class Student extends Person {
      def makeFriends(s: Student) {
        println("Hi, my name is " + name + ", your name is " + s.name)
      }
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Person
    defined class Student
    
    scala> val s1 = new Student
    s1: Student = Student@63355449
    
    scala> val s2 = new Student
    s2: Student = Student@1ab3a8c8
    
    scala> s1.makeFriends(s2)
    Hi, my name is leo, your name is leo
    
    
    
    
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Person {
      protected[this] val name: String  = "leo"
    }
    
    class Student extends Person {
      def makeFriends(s: Student) {
        println("my name is " + name + ", your name is " + s.name)
      }
    }
    
    // Exiting paste mode, now interpreting.
    
    <console>:22: error: value name is not a member of Student
               println("my name is " + name + ", your name is " + s.name)
                                                                    ^


    8、调用父类的constructor

    // Scala中,每个类可以有一个主constructor和任意多个辅助constructor,而每个辅助constructor的第一行都必须是调用其他辅助constructor或者是主constructor;
    因此子类的辅助constructor是一定不可能直接调用父类的constructor的
    // 只能在子类的主constructor中调用父类的constructor,以下这种语法,就是通过子类的主构造函数来调用父类的构造函数
    // 注意!如果是父类中接收的参数,比如name和age,子类中接收时,就不要用任何val或var来修饰了,否则会认为是子类要覆盖父类的field
    
    
    ###
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Person(val name: String, val age: Int)
    
    class Student(name: String, age: Int, var score: Double) extends Person(name, age) {
      def this(name: String) {
        this(name, 0, 0.0)
      }
      def this(age: Int) {
        this("leo", age, 0)
      }
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Person
    defined class Student
    
    scala> val s = new Student("leo", 30, 100)
    s: Student = Student@783a467b
    
    scala> s.name
    res6: String = leo
    
    scala> s.age
    res7: Int = 30
    
    scala> s.score
    res8: Double = 100.0
    
    scala> val s2 = new Student("leo")
    s2: Student = Student@6f204a1a
    
    scala> s2.name
    res9: String = leo
    
    scala> s2.age
    res10: Int = 0
    
    scala> val s3 = new Student(30)
    s3: Student = Student@3224a577
    
    scala> s3.name
    res11: String = leo
    
    scala> s3.age
    res12: Int = 30
    
    scala> s3.score
    res13: Double = 0.0


    9、匿名子类

    // 在Scala中,匿名子类是非常常见,而且非常强大的。Spark的源码中也大量使用了这种匿名子类。
    // 匿名子类,也就是说,可以定义一个类的没有名称的子类,并直接创建其对象,然后将对象的引用赋予一个变量。之后甚至可以将该匿名子类的对象传递给其他函数。
    
    
    ###
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Person(protected val name: String) {
      def sayHello = "Hello, I'm " + name
    }
    
    val p = new Person("leo") {
      override def sayHello = "Hi, I'm " + name
    }
    
    def greeting(p: Person {def sayHello: String}) {
      println(p.sayHello)
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Person
    p: Person = $anon$1@3f270e0a
    greeting: (p: Person{def sayHello: String})Unit
    
    scala> greeting(p)
    Hi, I'm leo


    10、抽象类

    // 如果在父类中,有某些方法无法立即实现,而需要依赖不同的子来来覆盖,重写实现自己不同的方法实现。此时可以将父类中的这些方法不给出具体的实现,
    只有方法签名,这种方法就是抽象方法。
    // 而一个类中如果有一个抽象方法,那么类就必须用abstract来声明为抽象类,此时抽象类是不可以实例化的
    // 在子类中覆盖抽象类的抽象方法时,不需要使用override关键字
    
    
    
    ###
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    abstract class Person(val name: String) {
      def sayHello: Unit
    }
    
    class Student(name: String) extends Person(name) {
      def sayHello: Unit = println("Hello, " + name)
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Person
    defined class Student
    
    scala> val p = new Person
    <console>:11: error: class Person is abstract; cannot be instantiated
           val p = new Person
                   ^
    
    scala> val s = new Student("leo")
    s: Student = Student@368239c8
    
    scala> s.sayHello
    Hello, leo


    11、抽象field

    // 如果在父类中,定义了field,但是没有给出初始值,则此field为抽象field
    // 抽象field意味着,scala会根据自己的规则,为var或val类型的field生成对应的getter和setter方法,但是父类中是没有该field的
    // 子类必须覆盖field,以定义自己的具体field,并且覆盖抽象field,不需要使用override关键字
    
    
    ###
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    abstract class Person {
      val name: String
    }
    
    class Student extends Person {
      val name: String = "leo"
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Person
    defined class Student
    
    scala> val s = new Student
    s: Student = Student@1794d431
    
    scala> s.name
    res1: String = leo
  • 相关阅读:
    Serialize and Deserialize Binary Tree
    sliding window substring problem汇总贴
    10. Regular Expression Matching
    《深入理解计算机系统》(CSAPP)读书笔记 —— 第七章 链接
    程序员如何写一份合格的简历?(附简历模版)
    9个提高代码运行效率的小技巧你知道几个?
    《深入理解计算机系统》(CSAPP)读书笔记 —— 第六章 存储器层次结构
    24张图7000字详解计算机中的高速缓存
    《深入理解计算机系统》(CSAPP)实验四 —— Attack Lab
    《深入理解计算机系统》(CSAPP)读书笔记 —— 第五章 优化程序性能
  • 原文地址:https://www.cnblogs.com/weiyiming007/p/11011096.html
Copyright © 2020-2023  润新知