1、将trait作为接口使用

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

    举例说明:

          
 

        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

          }

        }

 
 

2、在trait中定义具体的方法

  • Scala中的trait不仅可以定义抽象方法,还可以定义具体的方法,此时 trait 更像是包含了通用方法的工具,可以认为trait还包含了类的功能。

    举例说明:

    /**

     * 比如 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]

      }

    }

 
 

3、在trait中定义具体field

  • Scala 中的 trait 可以定义具体的 field,此时继承 trait 的子类就自动获得了 trait 中定义的 field;
  • 但是这种获取 field 的方式与继承 class 的是不同的。 如果是继承 class 获取的 field ,实际上还是定义在父类中的;而继承 trait获取的 field,就直接被添加到子类中了。

    举例说明:

        
 

        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

          }

 
 

}

4、在trait中定义抽象field

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

    举例说明:

 
 

    trait SayHelloTrait {

      val msg:String

      def sayHello(name: St

    ring) = 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)

      }

    }

 
 

5、在实例对象指定混入某个trait

  • 可在创建类的对象时,为该对象指定混入某个trait,且只有混入了trait的对象才具有trait中的方法,而其他该类的对象则没有;
  • 在创建对象时,使用 with 关键字指定混入某个 trait;

    举例说明:

    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!

      }

    }

6、trait 调用链

  • Scala中支持让类继承多个trait后,可依次调用多个trait中的同一个方法,只要让多个trait中的同一个方法,在最后都依次执行 super 关键字即可;
  • 类中调用多个trait中都有的这个方法时,首先会从最右边的trait的方法开始执行,然后依次往左执行,形成一个调用链条;
  • 这种特性非常强大,其实就是设计模式中责任链模式的一种具体实现;

    案例说明:

    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

      }

    }

7、混合使用 trait 的具体方法和抽象方法

  • 在 trait 中,可以混合使用具体方法和抽象方法;
  • 可以让具体方法依赖于抽象方法,而抽象方法则可放到继承 trait的子类中去实现;
  • 这种 trait 特性,其实就是设计模式中的模板设计模式的体现;

    举例说明:

    trait ValidTrait {

     //抽象方法

      def getName: String    

    //具体方法,具体方法的返回值依赖于抽象方法

                            
 

     def valid: Boolean = {"Tom".equals(this.getName)

      }

    }

    class PersonForValid(val name: String) extends ValidTrait {

      def getName: String = this.name

    }

    
 

    object PersonForValid{

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

        val person = new PersonForValid("Rose")

        println(person.valid)

      }

    }

 
 

 
 

8、trait的构造机制

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

    举例说明:

        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!

          }

        }

 
 

9、trait 继承 class

  • 在Scala中trait 也可以继承 class,此时这个 class 就会成为所有继承该 trait 的子类的超级父类。

    举例说明:

        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

          }

        }

 

scala当中的特质trait的更多相关文章

  1. Scala学习笔记--特质trait

    http://outofmemory.cn/scala/scala-trait-introduce-and-example 与Java相似之处 Scala类型系统的基础部分是与Java非常相像的.Sc ...

  2. Scala学习十——特质

    一.本章要点 类可以实现任意数量的特质 特质可以要求实现它们的类具备特定的字段,方法或超类 和Java接口不同,Scala特质可以提供方法和字段实现 当你将多个特质叠加在一起时,顺序很重要——其方法先 ...

  3. scala当中的类型参数

    类型参数主要就是研究scala当中的类或者scala当中的方法的泛型 1.scala当中的类的泛型         object Demo8 {          def main(args: Arr ...

  4. scala当中的对象

    1.scala当中的Object 在scala当中,没有类似于像java当中的static修饰的静态属性或者静态方法或者静态代码块之类的,但是我们可以通过scala当中的Object来实现类似的功能. ...

  5. scala当中的文件操作和网络请求

    1.读取文件当中每一行的数据 def main(args: Array[String]): Unit = { //注意文件的编码格式,如果编码格式不对,那么读取报错 val file: Buffere ...

  6. scala当中的类

    1.类的定义与创建 创建一个scala class来定义我们的一个类.类当中可以定义各种属性或者方法,或者函数都可以     class Person {       //定义一个属性,叫做name的 ...

  7. scala当中的Actor并发编程

    注:Scala Actor是scala 2.10.x版本及以前版本的Actor. Scala在2.11.x版本中将Akka加入其中,作为其默认的Actor,老版本的Actor已经废弃. 1.什么是Sc ...

  8. scala学习手记31 - Trait

    不知道大家对java的接口是如何理解的.在我刚接触到接口这个概念的时候,我将接口理解为一系列规则的集合,认为接口是对类的行为的规范.现在想来,将接口理解为是对类的规范多少有些偏颇,更恰当些的观点应该是 ...

  9. Beginning Scala study note(7) Trait

    A trait provides code reusability in Scala by encapsulating method and state and then offing possibi ...

随机推荐

  1. ASP.NET Core 中的依赖注入

    目录 什么是依赖注入 ASP .NET Core 中使用依赖注入 注册 使用 释放 替换为其它的 Ioc 容器 参考 什么是依赖注入 软件设计原则中有一个依赖倒置原则(DIP),为了更好的解耦,讲究要 ...

  2. R语言统计字符串的字符数ncahr函数

    函数计算字符数量,包括在一个字符串的空格的个数. 语法 nchar()函数的基本语法是: nchar(x) 以下是所使用的参数的说明: x - 向量输入. 示例 result <- nchar( ...

  3. 有线mac 无线MAC 地址&&telnet要先开服务: ipconfig /all getma

    在向IEEE申请到Mac address后,写到Lan设备里,就是Lan Mac,写到Wlan设备里,就是wlan Mac,写到BT设备里,就是BT Mac. MAC(Media Access Con ...

  4. i.mx android6 输入子系统分析(未完)

    参考:http://blog.csdn.net/u010312937/article/details/53285286 https://www.jianshu.com/p/7fca94b330ea   ...

  5. Android 直接通过JNI访问驱动

    package com.yang.jniaccesshardware; import android.os.Bundle; import android.support.v7.app.AppCompa ...

  6. Modbus Com SerialPort

    项目中用到的工具,串口modbus协议读写数据. public class ModbusHelper { private readonly SerialPort _serialPort; privat ...

  7. jQuery 数据 - jQuery.data() 方法

    打印出 hi

  8. Python——基本的方法

    格式化 我们经常会输出类似'亲爱的xxx你好!你xx月的话费是xx,余额是xx'之类的字符串,而xxx的内容都是根据变量变化的,所以,需要一种简便的格式化字符串的方式 >>> 'He ...

  9. 记一次吐血的暴力模拟qaq 【多项式输出】

    题目描述 一元 n 次多项式可用如下的表达式表示: 其中,aixi称为 i 次项,ai 称为 i 次项的系数.给出一个一元多项式各项的次数和系数,请按照如下规定的格式要求输出该多项式: 1. 多项式中 ...

  10. 时间复杂度为O(logN)的常用算法

    时间复杂度为O(logN)的常用算法 折半查找 /* * 折半查找 * 默认查找的数组已经排过序 */ public static int binarySearch(int[] a,int x){ i ...