zoukankan      html  css  js  c++  java
  • Scala 面向对象(二)construct+抽象类+接口trait

    1.1.1.    Scala中调用父类的constructor

    • Scala中,每个类都可以有一个主constructor和任意多个辅助constructor,而且每个辅助constructor的第一行都必须调用其他辅助constructor或者主constructor代码;因此子类的辅助constructor是一定不可能直接调用父类的constructor的;

     

    • 只能在子类的主constructor中调用父类的constructor。
    • 如果父类的构造函数已经定义过的 field,比如name和age,子类再使用时,就不要用 val 或 var 来修饰了,否则会被认为,子类要覆盖父类的field,且要求一定要使用 override 关键字。
    • 举例说明:

    package cn.gec.extends_demo
    class Person7(val name:String,val age:Int){
      var score :Double=0.0
      var address:String="beijing"
      def this(name:String,score:Double)={
        //每个辅助constructor的第一行都必须调用其他辅助constructor或者主constructor代码
        //主constructor代码
          this(name,30)
          this.score=score
      }
      //其他辅助constructor
      def this(name:String,address:String)={
          this(name,100.0)
          this.address=address
      }
    }
    class Student7(name:String,score:Double) extends Person7(name,score)

    
    

     

    1.1.2.     Scala中抽象类

    • 如果在父类中,有某些方法无法立即实现,而需要依赖不同的子类来覆盖,重写实现不同的方法。此时,可以将父类中的这些方法编写成只含有方法签名,不含方法体的形式,这种形式就叫做抽象方法;
    • 一个类中,如果含有一个抽象方法或抽象field,就必须使用abstract将类声明为抽象类,该类是不可以被实例化的;
    • 在子类中覆盖抽象类的抽象方法时,可以不加override关键字;
    • 举例说明:
    
    
    package cn.gec.extends_demo

    abstract class Person9(val name:String) {

      //必须指出返回类型,不然默认返回为Unit
     
    def sayHello:String

      def sayBye:String
    }
    classStudent9(name:String) extends Person9(name){
      //必须指出返回类型,不然默认
      def sayHello: String = "Hello,"+name
      def sayBye: String ="Bye,"+name
    }
    object Student9{
      def main(args: Array[String]) {
        val s = new Student9("tom")
        println(s.sayHello)
        println(s.sayBye)
      }
    }

    
    

     

     

     

    1.1.3.     Scala中抽象field

    • 如果在父类中,定义了field,但是没有给出初始值,则此field为抽象field;
    • 举例说明:

    package cn.gec.extends_demo
    abstract class Person10 (val name:String){
    //抽象fields
        val age:Int
    }
    class Student10(name: String) extends Person10(name) {
       val age: Int = 50
    }

    
    
     

     

    1.2.  Scala中面向对象编程之trait

    1.2.1.    将trait作为接口使用

    • Scala中的trait是一种特殊的概念;
    • 首先先将trait作为接口使用,此时的trait就与Java中的接口 (interface)非常类似;
    • 在trait中可以定义抽象方法,就像抽象类中的抽象方法一样,只要不给出方法的方法体即可;
    • 类可以使用extends关键字继承trait,注意,这里不是 implement,而是extends ,在Scala中没有 implement 的概念,无论继承类还是trait,统一都是 extends;
    • 类继承后,必须实现其中的抽象方法,实现时,不需要使用 override 关键字;
    • Scala不支持对类进行多继承,但是支持多重继承 trait,使用 with 关键字即可。
    • Class A extends class B
    • Class A extends class C
    • 举例说明:

    package cn.gec.triat
    trait HelloTrait {
      def sayHello(): Unit
    }
    trait MakeFriendsTrait {
      def makeFriends(c: Children): Unit
    }
    //多重继承 trait
    class Children(val name: String) extends HelloTrait with MakeFriendsTrait with Cloneable with Serializable{
      def sayHello() =println("Hello, " + this.name)
      def makeFriends(c: Children) = println("Hello, my name is " + this.name + ", your name is " + c.name)
    }
    object Children{
      def main(args: Array[String]) {
        val c1=new Children("tom")
        val c2=new Children("jim")
        c1.sayHello()//Hello, tom
        c1.makeFriends(c2)//Hello, my name is tom, your name is jim
      }
    }

    
    

     

    1.2.2.    在trait中定义具体的方法

    • Scala中的trait不仅可以定义抽象方法,还可以定义具体的方法,此时 trait 更像是包含了通用方法的工具,可以认为trait还包含了类的功能。
    • 举例说明:
    • Scala 中的 trait 可以定义具体的 field,此时继承 trait 的子类就自动获得了 trait 中定义的 field;
    • 但是这种获取 field 的方式与继承 class 的是不同的。 如果是继承 class 获取的 field ,实际上还是定义在父类中的;而继承 trait获取的 field,就直接被添加到子类中了。
    • 举例说明:

    package cn.gec.triat
    
    /**
     *
    比如 trait 中可以包含很多子类都通用的方法,例如打印日志或其他工具方法等等。
     
    * spark就使用trait
    定义了通用的日志打印方法;
     
    */
    trait Logger {

      def log(message: String): Unit = println(message)
    }
    class PersonForLog(val name: String) extends Logger {
      def makeFriends(other: PersonForLog) = {
        println("Hello, " + other.name + "! My name is " + this.name + ", I miss you!!")
        this.log("makeFriends method is invoked with parameter PersonForLog[name = " + other.name + "]")
      }
    }
    object PersonForLog{
      def main(args: Array[String]) {
        val p1=new PersonForLog("jack")
        val p2=new PersonForLog("rose")
        p1.makeFriends(p2)
        //Hello, rose! My name is jack, I miss you!!
        //makeFriens method is invoked with parameter PersonForLog[name = rose]
      }
    }

    
    

    1.2.3.    在trait中定义具体field

     


    package cn.gec.triat

    trait PersonForField {

      val  age:Int=50
    }

    //继承 trait 获取的field直接被添加到子类中
    class StudentForField(val name: String) extends PersonForField {
      def sayHello = println("Hi, I'm " + this.name + ", my  age  is "+ age)
    }

    object StudentForField{
      def main(args: Array[String]) {
        val s=new StudentForField("tom")
        s.sayHello
      }
    }

    
    
     

    1.2.4.    在trait中定义抽象field

    • Scala中的trait也能定义抽象field, 而trait中的具体方法也能基于抽象field编写;
    • 继承trait的类,则必须覆盖抽象field,提供具体的值;
    • 举例说明:

    package cn.gec.triat

    trait SayHelloTrait {

      val msg:String
      def sayHello(name: String) = println(msg + ", " + name)
    }

    class PersonForAbstractField(val name: String) extends SayHelloTrait {
      //必须覆盖抽象 field
      val msg = "Hello"
      def makeFriends(other: PersonForAbstractField) = {
        this.sayHello(other.name)
        println("I'm " + this.name + ", I want to make friends with you!!")
      }
    }
    object PersonForAbstractField{
      def main(args: Array[String]) {
        val p1=new PersonForAbstractField("Tom")
        val p2=new PersonForAbstractField("Rose")
        p1.makeFriends(p2)
      }
    }

    
    

     

    1.2.5.    在实例对象指定混入某个trait

    • 可在创建类的对象时,为该对象指定混入某个trait,且只有混入了trait的对象才具有trait中的方法,而其他该类的对象则没有;
    • 在创建对象时,使用 with 关键字指定混入某个 trait; 
    • 举例说明:
    • Scala中支持让类继承多个trait后,可依次调用多个trait中的同一个方法,只要让多个trait中的同一个方法,在最后都依次执行 super 关键字即可;
    • 类中调用多个trait中都有的这个方法时,首先会从最右边的trait的方法开始执行,然后依次往左执行,形成一个调用链条;
    • 这种特性非常强大,其实就是设计模式中责任链模式的一种具体实现;
    • 案例说明:

    
    
    package cn.gec.triat
    trait LoggedTrait {
      // 该方法为实现的具体方法
      def log(msg: String) = {}
    }
    trait MyLogger extends LoggedTrait{
      // 覆盖 log() 方法
    override def log(msg: String) = println("log: " + msg)
    }

    class PersonForMixTraitMethod(val name: String) extends LoggedTrait {
      def sayHello = {
        println("Hi, I'm " + this.name)
        log("sayHello method is invoked!")
      }
    }
    object PersonForMixTraitMethod{
      def main(args: Array[String]) {
        val tom= new PersonForMixTraitMethod("Tom").sayHello //结果为:Hi, I'm Tom
        // 使用 with 关键字,指定混入MyLogger trait
        val rose = new PersonForMixTraitMethod("Rose") with MyLogger
        rose.sayHello
    // 结果为:     Hi, I'm Rose
    // 结果为:     log: sayHello method is invoked!
      }
    }

    
    

    1.2.6.    trait 调用链


    
    
    package cn.gec.triat
    trait HandlerTrait {
      def handle(data: String) = {println("last one")}
    }
    trait DataValidHandlerTrait extends HandlerTrait {
      override def handle(data: String) = {
                  println("check data: " + data)
                  super.handle(data)
    }
    }
    trait SignatureValidHandlerTrait extends HandlerTrait {
      override def handle(data: String) = {
              println("check signature: " + data)
              super.handle(data)
      }
    }
    class PersonForRespLine(val name: String) extends SignatureValidHandlerTrait with DataValidHandlerTrait {
      def sayHello = {
            println("Hello, " + this.name)
            this.handle(this.name)
      }
    }
    object PersonForRespLine{
      def main(args: Array[String]) {
         val p=new PersonForRespLine("tom")
          p.sayHello
          //执行结果:
    //    Hello, tom
    //    check data: tom
    //    check signature: tom
    //    last one
      }
    }

    
    

     

     

    1.2.7.    trait的构造机制

    • 在Scala中,trait也是有构造代码的,即在trait中,不包含在任何方法中的代码;
    • 继承了trait的子类,其构造机制如下:
    • 父类的构造函数先执行, class 类必须放在最左边;多个trait从左向右依次执行;构造trait时,先构造父 trait,如果多个trait继承同一个父trait,则父trait只会构造一次;所有trait构造完毕之后,子类的构造函数最后执行。
    • 举例说明:

    
    
    package cn.gec.triat
    class Person_One {
      println("Person's constructor!")
    }
    trait Logger_One {
      println("Logger's constructor!")
    }
    trait MyLogger_One extends Logger_One {
      println("MyLogger's constructor!")
    }
    trait TimeLogger_One extends Logger_One {
      println("TimeLogger's contructor!")
    }
    class Student_One extends Person_One with MyLogger_One with TimeLogger_One {
      println("Student's constructor!")
      }
    object exe_one {
      def main(args: Array[String]): Unit = {
        val student = new Student_One
        //执行结果为:
    //      Person's constructor!
    //      Logger's constructor!
    //      MyLogger's constructor!
    //      TimeLogger's contructor!
    //      Student's constructor!
      }
    }

    
    

     

    1.2.8.    trait 继承 class

    • 在Scala中trait 也可以继承 class,此时这个 class 就会成为所有继承该 trait 的子类的超级父类。
    • Class A
    • Trait B extends A
    • Class C extends B
    • Trait D extends B
    • 举例说明:

    
    
    package cn.gec.triat
    class MyUtil {
      def printMsg(msg: String) = println(msg)
    }
    trait Logger_Two extends MyUtil {
      def log(msg: String) = this.printMsg("log: " + msg)
    }
    class Person_Three(val name: String) extends Logger_Two {
        def sayHello {
            this.log("Hi, I'm " + this.name)
            this.printMsg("Hello, I'm " + this.name)
      }
    }
    object Person_Three{
      def main(args: Array[String]) {
          val p=new Person_Three("Tom")
          p.sayHello
        //执行结果:
    //      log: Hi, I'm Tom
    //      Hello, I'm Tom
      }
    }

    
    
    
    

     

     

     

  • 相关阅读:
    python,生产环境安装
    neo4j 图数据库
    RNN系列
    机器学习关于AUC的理解整理
    fensorflow 安装报错 DEPENDENCY ERROR
    dubbo Failed to check the status of the service com.user.service.UserService. No provider available for the service
    使用hbase遇到的问题
    MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk
    gradle 安装
    jenkins 安装遇到的坑
  • 原文地址:https://www.cnblogs.com/Transkai/p/10968809.html
Copyright © 2011-2022 走看看