scala开发快速入门 | 第六篇 面向对象编程(下)

trait简介

在scala中并没有提供java语言的interface关键字来定义接口,而是可以使用trait实现多重继承,继承的时候使用extends和with关键字。

/*定义三个trait*/
trait TraitDemo01 {
//  抽象方法定义
  def say(content:String):Unit

}
trait TraitDemo02{
  //抽象方法定义
  def sayHello(content:String):Unit
}

trait TraitDemo03{
  //抽象方法定义
  def sayGoodBye(content:String):Unit

}

//trait 作为接口使用 那么必须实现trait的抽象方法
class TraitDemo04 extends TraitDemo01 with TraitDemo02 with TraitDemo03 {
//  类实现trait的抽象方法 可以省略 override关键字
  override def say(content: String): Unit = {
    println(content)

  }
  override def sayHello(content: String): Unit = {
    println(content)

  }
  override def sayGoodBye(content: String): Unit = {
    println(content)

  }
}
object Application05{
  def main(args: Array[String]): Unit = {
    val t1=new TraitDemo04
    t1.say("say everything !")
    t1.sayHello("say  hello!")
    t1.sayGoodBye("say GoodBye!")

  }

}

trait中定义方法和字段

1)trait中除了能够定义抽象的字段和抽象方法外,还能定义非抽象的字段和方法    

2)和抽象类的唯一区别就是抽象类是单继承,而trait是多实现。

实例对象中混入trait

实例对象混入 trait 那么这个实例对象就拥有了trait的所有非私有方法。

/*实例对象中混入trait*/
trait TraitDemo05 {

  def say() = {
    println("say hello !")

  }
}
/*一个类继承了父类或者trait,那么这个类拥有该类或者trait的所有非私有的方法*/
class Baby(var name: String, var age: Int) {

}
object Application005 {
  def main(args: Array[String]): Unit = {

    val b1 = new Baby("xiaoming", 25)
    //为实例对象混入 trait 那么这个实例对象就拥有了trait的所有非私有方法
    val b2 = new Baby("xiaohua", 26) with TraitDemo05
    b2.say()
  }
}

继承trait的构造构造机制

trait TraitDemos {
  println("这是TraitDemo03 的主代码块!")

}
trait TraitDemos01 extends TraitDemos {
  println("这是TraitDemo04 的主代码块!")

}
trait TraitDemos02 extends TraitDemos{
  println("这是TraitDemo05 的主代码块!")

}
class Persons01{
  println("这个Person01的 主代码块!")

}
class Students01 extends Persons01 with TraitDemos01 with TraitDemos02{
  println("这是 Students01的主代码块 !")

}
object Students01{
  def main(args: Array[String]): Unit = {
    /**子类继承了(类和trait)的构造机制如下
      * 1、执行父类的构造代码块
      * 2、执行trait的构造代码块,如果是多个trait那么从左到右执行trait的代码块
      *    如果多个trait继承了同一个trait那么先执行父trait的构造代码,然后执行子trait的构造代码
      *    trait的构造代码只执行一次
      * 3、 最后执行自己的构造代码,即:子类的构造代码块最后执行*/
    val s1=new Students01
  }
}

泛型

在创建类和方法的时候可以指定类和方法的泛型。

泛型类

class FanXing[T1,T2,T3](var name:T1) {

  def say(): Unit ={
    println(name)

  }
  var age:T2=_
  var sex:T3=_

}
object FanXing{
  def main(args: Array[String]): Unit = {
    val s=new FanXing[String,Int,String]("ysj")
    s.say()
    s.age=18
    s.sex="man"
    println("name="+s.name+" "+"age="+s.age+" "+"sex"+s.sex)
  }
}

泛型函数

/*泛型方法*/
class FanXingFunction {
  def say[T1, T2, T3](name: T1, age: T2): T3 = {
    (name + "=" + age).asInstanceOf[T3]
  }
}
object FanXingFunction {
  def main(args: Array[String]): Unit = {
    val f = new FanXingFunction
    var result = f.say[String, Int, String]("xiaoming", 25)
    println(result)
  }
}

泛型类的上边界

class Persons03
class Teacher03 extends Persons03
class Student03 extends Persons03

class Animal03
class Dog03 extends Animal03
class Cat03 extends Animal03

/*上边界 <: 即泛型T只能是 Person03Person03的子类*/
class FanXingUpBound[T <: Persons03] {
  def say(content:T) ={
    println(content.getClass)
  }
}
object FanXingUpBound{
  def main(args: Array[String]): Unit = {
    val f1=new FanXingUpBound[Persons03]
    val t1=new Teacher03
    val s1=new Student03
    f1.say(t1)
    f1.say(s1)
    val f2=new FanXingUpBound[Teacher03]
    f2.say(t1)
    val f3=new FanXingUpBound[Student03]
    f3.say(s1)
    /*以下代码错误 因为animal不属于Person03或其子类 不能作为FanXingUpBound的泛型*/
//    val animal=new FanXingUpBound[Animal03]
  }
}

泛型类的下边界

class Master

class Professor extends Master

class Teacher extends Professor

/*下边界 >: T只能是Professor及其Professor的父类*/
class FanXingDownBound[T >: Professor] {
  def say(content: T): Unit = {
    println(content.getClass)
  }
}

object FanXingDownBound {
  def main(args: Array[String]): Unit = {
    //    Master 可以作为FanXingDownBound泛型 以为MasterProfessor的父类
    val f1 = new FanXingDownBound[Master]
    //    Professor也可以作为FanXingDownBound泛型 因为Professor就是要求我们传入的泛型
    val f2 = new FanXingDownBound[Professor]
    //Teacher 不能作为FanXingDownBound泛型 因为Teacher 不是Professor以及Professor的父类
    val f3 = new FanXingDownBound[Teacher]
  }
}

泛型协变

1)斜变在scala中是一种特色的功能,他完美的解决了java泛型的缺陷。

2)比如 Professor是Master的子类 那么     Card[Professor] 是不是 card[Master]的子类呢? java是无法实现的但是scala的协变解决了此问题。

3)scala协变是泛型类上边界的加强版

class Master05

class Professor05 extends Master05

class Teacher05

/*这个是协变 ProfessorMaster的子类 那么Card[Professor] 也是Card[Master] 的子类*/
class Card[+T]

class FanXingXieBian {
  def say(card: Card[Master05]): Unit = {
    println("只要Master级别 以及下一级别的才能入场!")
  }

}
object FanXingXieBian{
  def main(args: Array[String]): Unit = {
    val cm=new Card[Master05]
    val cp=new Card[Professor05]
    val ct=new Card[Teacher05]

    val fx=new FanXingXieBian
    fx.say(cm)
    fx.say(cp)
//    fx.say(ct) 编译报错
  }
}

泛型逆变

1)逆变在scala中也是一种特色的功能,他完美的解决了java泛型的缺陷。

2)比如 Professor是Master的子类 那么 Card[Professor] 是不是 card[Master]的子类呢? java是无法实现的但是scala的逆变解决了此问题。

3)scala逆变是泛型类下边界的加强版

class Master06
class Professor06 extends Master06
class Teacher06 extends Professor06
/*这个是逆变 ProfessorMaster的子类 那么Card[Professor] 也是Card[Master] 的子类*/
class Card[-T]
class FanXingNiBian {

  def say(card: Card[Professor06]): Unit = {
    println("只要Professor06级别 以及上一级别的才能入场!")
  }

}
object FanXingNiBian{
  def main(args: Array[String]): Unit = {
    val cm=new Card[Master06]
    val cp=new Card[Professor06]
    val ct=new Card[Teacher06]

    val fx=new FanXingNiBian
    fx.say(cm)
    fx.say(cp)
//    fx.say(ct) 编译报错
  }
}



猜你喜欢

转载自blog.csdn.net/yangshaojun1992/article/details/80951770