scala 学习笔记(05) OOP(中)灵活的trait

简介: trait -- 不仅仅只是接口! 接上回继续,scala是一个非常有想法的语言,从接口的设计上就可以发现它的与众不同。scala中与java的接口最接近的概念是trait,见下面的代码: package yjmyzz object App { def main(args...

trait -- 不仅仅只是接口!

上回继续,scala是一个非常有想法的语言,从接口的设计上就可以发现它的与众不同。scala中与java的接口最接近的概念是trait,见下面的代码:

package yjmyzz


object App {

  def main(args: Array[String]) {
    val bird = Bird("pigeon")
    bird.fly
    println(bird.isInstanceOf[Bird]) //true
    println(bird.isInstanceOf[Flyable]) //true
    println(bird.toString) //this is a Bird:pigeon
    bird.test //hello
  }
}

/**
 * 定义一个"接口"
 */
trait Flyable {

  /**
   * 定义接口方法
   */
  def fly;


  /**
   * 接口中也有可以方法的实现(是不是惊呆了!)
   * @return
   */
  def test = {
    println("hello")
  }
}


class Bird(var name: String) extends Flyable {
  /**
   * 实现接口中的方法
   */
  def fly: Unit = {
    println("I am a " + name + ", and I can fly~")
  }

  override def toString = {
    "this is a Bird:" + name
  }
}

object Bird {
  def apply(name: String) = {
    new Bird(name)
  }

}

从上面的代码中,可以看出trait与java中interface的异同,相同的是如果把trait单纯当接口来用,trait中只需要定义方法签名即可,然后由"子类"来实现。不同的是,scala中的trait里也可以有方法实现!而且实现接口时,关键字不是implements而是extends(当然,还可能是with,后面还会提到),这说明scala中trait并不仅仅只是接口,它也是一种特殊的类

trait的mixin:

trait还有一个神奇的特性,可以在运行时,动态与其它类合体!见下面的代码:

package yjmyzz


object App {

  def main(args: Array[String]) {
    val duck = new Bird("duck") with Swim
    println(duck.isInstanceOf[Flyable]) //true
    println(duck.isInstanceOf[Swim]) //true 注意这里:表示此时Bird也是一个Swim实例
    duck.fly //I am a duck, and I can fly~
    duck.swim //I can swim! 注:是不是很有意思,绝对的动态晚绑定!
  }
}

/**
 * 定义一个"接口"
 */
trait Flyable {

  /**
   * 定义接口方法
   */
  def fly;


  /**
   * 接口中也有可以方法的实现(是不是惊呆了!)
   * @return
   */
  def test = {
    println("hello")
  }
}


/**
 * 再来一个"接口"
 */
trait Swim {
  def swim = {
    println("I can swim!")
  }
}


class Bird(var name: String) extends Flyable {

  /**
   * 实现接口中的方法
   */
  def fly: Unit = {
    println("I am a " + name + ", and I can fly~")
  }

  override def toString = {
    "this is a Bird:" + name
  }
}

我们又新增了一个trait:Swim,然后注意第7行,通过with Swim,硬是把跟Swim毫不相关的Bird实例跟它搅在一起了,然后实例duck就获得了Swim的能力! 这种场景下,trait就不应该理解为接口,而应该认为它是一种特性,是一种可以动态赋予其它实例的超能力!(这也是为什么关键字不叫interface,而是叫trait的原因吧)

trait与java中的接口还有一个明显的区别,trait可以继承自类,java中的interface可是不允许继承自class的! 见下面的代码示例:

package yjmyzz

/**
 * 动物基类
 */
class Animal {}

/**
 * 会飞的动物("接口"继承类)
 */
trait FlyAnimal extends Animal {
  def fly;
}

/**
 * 即会飞又会游泳的动物("接口"继承"接口")
 */
trait SwimAndFlyAnimal extends FlyAnimal {
  def swim;
}

/**
 * 会说话(注:这个接口是完全独立的,不继承自任何其它类或trait)
 */
trait Talk {
  def talk;
}

/**
 * 鸟(继承类,又实现"接口",实际上是多重继承)
 */
class Bird(var birdName: String) extends Animal with FlyAnimal {
  override def fly: Unit = {
    println(birdName + "能飞!")
  }
}

/**
 * 被继承的class[Animal]与trait[Talk]相互之间也可以没半毛钱关系
 */
class AlienAnimal extends Animal with Talk {
  override def talk: Unit = println("外星动物很厉害的啦,它们会说话!")
}

/**
 * 类也可以直接继承自trait
 */
class TalkThing extends Talk {
  override def talk: Unit = println("我也不知道我是啥,反正我会说话!")
}

object ScalaApp {

  def main(args: Array[String]) {

    var eagle = new Bird("老鹰")
    eagle.fly

    println

    var swan = new Bird("天鹅") with SwimAndFlyAnimal {
      override def swim: Unit = println("天鹅还能游泳!")
    }
    swan.fly
    swan.swim

    println

    var sparrow = new Bird("麻雀") with Talk {
      override def talk: Unit = println {
        "麻雀'说话',就是叽叽喳喳的叫!"
      }
    }
    sparrow.fly
    sparrow.talk

    println

    var alienAnimal = new AlienAnimal
    alienAnimal.talk

    println

    var talkThing = new TalkThing
    talkThing.talk


  }

}

运行结果:

老鹰能飞!

天鹅能飞!
天鹅还能游泳!

麻雀能飞!
麻雀'说话',就是叽叽喳喳的叫!

外星动物很厉害的啦,它们会说话!

我也不知道我是啥,反正我会说话!


关于trait,小结一下:

1、trait"类似"(注:仅仅只是类似)java中的接口,可以只定义方法签名,交由子类去实现

2、trait中也可以有具体的方法实现

3、trait可以继承自trait,也可以继承自class

4、class也可以直接继承自trait

5、trailt可以在运行时,通过with关键,动态混入class实例

目录
相关文章
|
6月前
|
机器学习/深度学习 JSON Java
Scala 02——Scala OOP
Scala 是一种纯粹的面向对象编程(OOP)语言,它不支持基本类型,所有数据都作为对象处理,即使在JVM上运行也会自动处理拆装箱。Scala 不包含静态关键字,其“静态”概念体现在类型系统和单例对象中,类型检查都在编译时完成。类型推断、类型预定和动静结合是其特点,例如,Scala 支持协变和逆变,使得泛型编程更加灵活。此外,Scala 的类、继承、抽象类、单例对象和泛型等特性提供了丰富的编程模型。例如,单例对象可以看作静态成员的替代品,同时具备惰性初始化和与类的绑定关系。
63 1
Scala 02——Scala OOP
|
6月前
|
Java Scala 容器
|
6月前
|
分布式计算 Java Scala
Scala:面向对象、Object、抽象类、内部类、特质Trait(二)
Scala:面向对象、Object、抽象类、内部类、特质Trait(二)
92 0
|
大数据 Scala 容器
【建议收藏】|3分钟让你学会Scala Trait 使用
Scala 是一种强大的静态类型编程语言,其中的 Trait 是一种重要的特性。Trait 可以被看作是一种包含方法和字段定义的模板,可以被其他类或 Trait 继承或混入。在本文中,我们将介绍 Scala Trait 的边界(Boundary)的概念,并展示如何使用它来限制 Trait 的使用范围。
257 11
|
分布式计算 Java 大数据
|
Java Scala
scala面向对象编程之trait特质
特质就像是java的implement,是scala中代码复用的基础单元,它可以将方法和字段定义封装起来,然后添加到类中与类继承不一样的是,类继承要求每个类都只能继承一个超类,而一个类可以添加任意数量的特质。特质的定义和抽象类的定义很像,但它是使用trait关键字
117 0
scala面向对象编程之trait特质
|
大数据 编译器 Scala
大数据开发基础的编程语言的Scala的Trait
Scala是一种支持面向对象编程和函数式编程的编程语言,它提供了强大的Trait功能。本文将介绍Scala中Trait的概念和用法,帮助开发者更好地理解和应用这门语言。
96 0
|
设计模式 XML Java
基于Scala Trait的设计模式
基于Scala Trait的设计模式
|
Java Scala 开发者
Scala 下界介绍和应用实例 | 学习笔记
快速学习 Scala 下界介绍和应用实例
Scala 下界介绍和应用实例 | 学习笔记
|
Scala 开发者
Scala 上界介绍和应用实例2 | 学习笔记
快速学习Scala上界介绍和应用实例2
Scala 上界介绍和应用实例2 | 学习笔记