ふじさん春原庄的雪

scala_Trait

木子山13·2020-05-09 19:27·214 次阅读

scala_Trait

Trait 的基本概念#

在 Scala中Trait 为重用代码的一个基本单位。一个 Traits 封装了方法和变量,和 Interface 相比,它的方法可以有实现,这一点有点和抽象类定义类似。但和类继承不同的是,Scala 中类继承为单一继承,也就是说子类只能有一个父类。当一个类可以和多个 Trait 混合,这些 Trait 定义的成员变量和方法也就变成了该类的成员变量和方法,由此可以看出 Trait 集合了 Interface 和抽象类的优点,同时又没有破坏单一继承的原则。

 

在类或者对象中混合了trait后便具有trait的方法和属性,此外被混合的类也可以重载 trait中的方法。语法与重载基类中定义的方法一样。

 

1.定义一个 Trait 的方法和定义一个类的方法非常类似,除了它使用 trait 而非 class 关键字来定义一个 trait。

复制代码
package Trat

trait HelloTrait {
  def sayHello(): Unit //抽象方法 没有具体的实现
}

trait MakeFriendsTrait {
  def makeFriends(c: Children): Unit  //参数是一个children对象
}

//多重继承 trait 如果你需要把某个 Trait 添加到一个有基类的子类中,使用 extends 继承基类,而可以通过 with 添加 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
  }
}
复制代码

运行结果:

Hello, tom
Hello, my name is tom, your name is jim

 

总结:Trait 就像是带有具体方法的 Java 接口,不过其实它能做的更多。Trait 可以,比方说,声明字段和维持状态值。实际上,你可以用 Trait 定义做任何用类定义做的事,并且语法也是一样的,除了一点。Trait 不能有任何“类”参数,也就是说,传递给类的主构造器的参数。参数可写在方法里。

 

2.

复制代码
package Trat

  trait LoggedTrait {
    // 该方法为实现的具体方法
    def log(msg: String) = {}
  }

  //trait间也可以相互混合
  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!") //调用的LoggedTrait中的log方法
    }
  }

object PersonForMixTraitMethod{
  def main(args: Array[String]) {
    val tom= new PersonForMixTraitMethod("Tom")
    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!
  }
}
复制代码

运行结果:

Hi, I'm Tom
Hi, I'm Rose
log: sayHello method is invoked!

 

3.trait 也可以继承 class

复制代码
package Trat

/*
在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
  }
}
复制代码

运行结果:

log: Hi, I'm Tom
Hello, I'm Tom

 

4.

复制代码
package Trat

/*
在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!
  }
}
复制代码

运行结果:

Person's constructor!
Logger's constructor!
MyLogger's constructor!
TimeLogger's contructor!
Student's constructor!

 

5.继承trait的类,则必须覆盖抽象field,提供具体的值

复制代码
package Trat

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

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)
  }
}
复制代码

运行结果:

Hello, Rose
I'm Tom, I want to make friends with you!!

 

6.继承 trait获取的 field,就直接被添加到子类中了

复制代码
package Trat

/*
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
  }
}
复制代码

运行结果:

Hi, I'm tom, my  age  is 50

 

7.让具体方法依赖于抽象方法,而抽象方法则可放到继承 trait的子类中去实现

复制代码
package Trat

/*
在 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)
  }
}
复制代码

运行结果:

false

 

8.多继承的同名歧义问题

复制代码
package Trat

/*
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, " + 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

 

posted @   li-shan  阅读(214)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示
目录