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
  }
}




 

 

 

posted @ 2019-06-03 17:17  Transkai  阅读(388)  评论(0编辑  收藏  举报