zoukankan      html  css  js  c++  java
  • Trait详解

    基础知识

    1. Trait(特征):是一种特殊的概念,相当于 Java 的接口,实际上它比接口还功能强大,它还可以定义属性和方法的实现

    2. Trait的定义:定义的方式和定义类的方式相同
    3. scala不支持对类进行多继承,但是支持多重继承trait,使用with关键字即可,解决类的单继承问题

    4. 类继承trait后,必须实现其中的抽象方法和抽象字段

    5. trait也可以继承自class,此时这个class就会成为所有继承该trait的类的父类

    抽象方法和抽象字段

    1. 在triat中可以定义抽象方法,定义的抽象方法可以直接在trait中引用
    2. Triat可以定义抽象field,定义的抽象字段可以在trait中直接引用,此时抽象字段有默认值
    object test11 {
      trait Sayhello{
        val name :String  //抽象字段
        println(name)  //调用抽象字段
        def sayhello(name:String)=println(s"hello,$name")  //具体方法调用抽象字段
      }
      trait MakeFriends{
        def makeFrinds(str:String)  //抽象方法
        def log(msg: String) {} //{}表示不是抽象方法
      }
      class Person(val name:String) extends Sayhello with MakeFriends{  //with实现多继承
        def makeFrinds(str:String)=print(s"可以交个朋友吗?$str")   //实现MakeFriends中的抽象方法
      }
      def main(args: Array[String]): Unit = {
        val person=new Person("Wei")
        person.sayhello("Tom")
        person.makeFrinds("Tom")
      }
    }

    具体方法和具体字段

    1. 就像普通类中的具体方法和具体字段一样
    object test12{
          trait Person {
            val age: Int = 2
            def eat(food: String) = println(s"吃 $food")
          }
          class Student(val name: String) extends Person {}
    
      def main(args: Array[String]): Unit = {
        val person = new Student("tom")
        println(person.age)
        person.eat("橘子")
      }
    }

    高级知识

    实例对象继承trait

    1. 创建对象的时候只需要某个实例对象继承trait,而不需要类中的其他对象继承trait
    2. 对象动态继承的trait会覆盖对象实现类的成员(Man覆盖了Person方法)
    object  test21{
      trait Person {
        def eat(food: String) {println("不喜欢吃"+food)}
      }
      trait Man extends Person {
        override def eat(food: String){println("喜欢吃"+food)}
      }
    
      class Teacher(val name: String) extends Person {
        def sayHello {
          println("你好,我是" + name)
          eat("水果") }
      }
      def main(args: Array[String]): Unit = {
        val p1 = new Teacher("wiki")
        p1.sayHello
        println("	")
        val p2 = new Teacher("jack") with Man
        p2.sayHello
      }
    }

    调用链

    1. 类继承traitA,traitA继承traitB,traitB继承traitC,traitC继承traitD,如果要同时调用trait[A-D]中相同的方法fun1,只要将只需要将super.fun1放入到fun1中即可,形成一个调用链条
    object  test22 {
      trait KeyWord {
        def logger(data: String): Unit = {
          println("第一次密码是:" + data)
        }
      }
      trait KeyWord1 extends KeyWord {
        override def logger(data: String): Unit = {
          println("第二次密码是:" + data)
          super.logger(data)
        }
      }
      trait KeyWord2 extends KeyWord1 {
        override def logger(data: String): Unit = {
          println("第三次密码是:" + data)
          super.logger(data)
        }
      }
      class KeyWord3 extends KeyWord2 {
        def log(data: String): Unit = {
          logger(data)
        }
      }
      def main(args: Array[String]): Unit = {
        val s = new KeyWord3
        s.log("car360")
      }
    }
    /**
      * 输出结果:
      * 第三次密码是:car360
      * 第二次密码是:car360
      * 第一次密码是:car360
      */

    abstract override

    1. trait可以直接引用抽象方法,但是子类中不可以直接引用父类的抽象方法,需要引用必须用abstract override修饰
    object  test23{
      trait Person {
        def play(str: String)
        def eat(str: String) { play(str) }
      }
      trait Teacher extends Person {
        abstract override def play(str: String) { super.play(str) }
        def eat(str: String) { super.eat(str) }   //会报错
            def say(str: String) { super.play(str) }
      }
    }

    构造机制

    1. trait也有构造函数
    2. 继承了trait的类的构造机制如下:
      1. 父类的构造函数先执行
      2. 类继承的traitA如果有父traitB,父traitB的构造代码先执行(多个trait继承同一个父trait,则父trait只会构造一次)
      3. trait的构造代码执行,多个trait从左到右依次执行
      4. 子类的构造函数执行
    object  test24{
      class Person { println("Person's constructor!") }
      trait Number { println("Number's constructor!") }
      trait First extends Number { println("First's constructor!") }
      trait Second extends Number { println("Second's constructor!") }
      class Student extends Person with First with Second {
        println("Student's constructor!")
      }
      def main(args: Array[String]): Unit = {
        val stu = new Student
      }
    }
    //运行结果:
    //Person's constructor!
    //Number's constructor!
    //First's constructor!
    //Second's constructor!
    //Student's constructor!

    字段的初始化

    1.  trait没有接收参数的构造函数
    2. trait中的抽象字段都有默认值
    3. 提前定义:在调用trait的构造函数时候重写了字段值
    4. lazy:不能用于抽象字段,只能用于具体字段

    方法一:提前定义

    object test25 {
      trait Person{
        val num:String
        println(num)  
        println(num.toInt+123)
      }
      class Student(number: String) extends Person{
        val num:String=number
        print("the new num is "+num)
      }
      def main(args: Array[String]): Unit = {
    //    val s= new Person("123") //会报错因为他会先执行trait的println num此时是null,这时就需要用到提前定义了
        val p = new {
          override val num: String = "123"
        } with Student("456")           //注意:传入的参数是123而不是456
      }
    }

    方法二:用lazy

    trait Person{
      lazy  val num:String=null //注意lazy不能用于抽象字段,只能用与具体字段
      println(num.toInt+123)
    }
    class Student (number: String) extends Person{
      override lazy val num:String=number
      print("the new num is "+num)
    }
    object test {
      def main(args: Array[String]): Unit = {
        val p = new Student("123")
      }
    }


  • 相关阅读:
    Java单例模式
    svn 清理失败 (clean up 失败) 的解决方法
    linux chrome 安装过程记录
    docker
    linux-cat-grep
    linux-批量结束进程
    linux-压缩与解压缩(gz,zip,tar,jar,war)
    git-服务器地址切换
    linux-tomcat连接数查询
    git-无法add文件的问题
  • 原文地址:https://www.cnblogs.com/WeiKing/p/11665480.html
Copyright © 2011-2022 走看看