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实例

scala 学习笔记(05) OOP(中)灵活的trait的更多相关文章

  1. scala 学习笔记(04) OOP(上)主从构造器/私有属性/伴生对象(单例静态类)/apply方法/嵌套类

    一.主从构造器 java中构造函数没有主.从之分,只有构造器重载,但在scala中,每个类都有一个主构造器,在定义class时,如果啥也没写,默认有一个xxx()的主构造器 class Person ...

  2. scala 学习笔记(06) OOP(下)多重继承 及 AOP

    一.多继承 上篇trait中,已经看到了其用法十分灵活,可以借此实现类似"多重继承"的效果,语法格式为: class/trait A extends B with C with D ...

  3. 基于.net的分布式系统限流组件 C# DataGridView绑定List对象时,利用BindingList来实现增删查改 .net中ThreadPool与Task的认识总结 C# 排序技术研究与对比 基于.net的通用内存缓存模型组件 Scala学习笔记:重要语法特性

    基于.net的分布式系统限流组件   在互联网应用中,流量洪峰是常有的事情.在应对流量洪峰时,通用的处理模式一般有排队.限流,这样可以非常直接有效的保护系统,防止系统被打爆.另外,通过限流技术手段,可 ...

  4. 机器学习实战(Machine Learning in Action)学习笔记————05.Logistic回归

    机器学习实战(Machine Learning in Action)学习笔记————05.Logistic回归 关键字:Logistic回归.python.源码解析.测试作者:米仓山下时间:2018- ...

  5. Scala学习笔记及与Java不同之处总结-从Java开发者角度

    Scala与Java具有很多相似之处,但又有很多不同.这里主要从一个Java开发者的角度,总结在使用Scala的过程中所面临的一些思维转变. 这里仅仅是总结了部分两种语言在开发过程中的不同,以后会陆续 ...

  6. C++ GUI Qt4学习笔记05

    C++ GUI Qt4学习笔记05   qtc++正则表达式 QIntValidator           --  只让用户输入整数 QDoubleValidator     --  只让用户输入浮 ...

  7. 并发编程学习笔记(4)----jdk5中提供的原子类及Lock使用及原理

    (1)jdk中原子类的使用: jdk5中提供了很多原子类,它会使变量的操作变成原子性的. 原子性:原子性指的是一个操作是不可中断的,即使是在多个线程一起操作的情况下,一个操作一旦开始,就不会被其他线程 ...

  8. [学习笔记] 在Eclipse中导入项目

    参考前文:[学习笔记] 在Eclips 中导出项目 选择已经导出的文件: 导入之后,项目结构如下: 至此,完成.

  9. CockroachDB学习笔记——[译]CockroachDB中的SQL:映射表中数据到键值存储

    CockroachDB学习笔记--[译]CockroachDB中的SQL:映射表中数据到键值存储 原文标题:SQL in CockroachDB: Mapping Table Data to Key- ...

随机推荐

  1. ios界面布局整理

    1 UIView 1.1 创建自定义的UIView的xib文件 [1]设置 file's Owner的 Custom Class 中的class 执行自定义控件类 [2]设置当前UIView 的屏幕大 ...

  2. Javascript之旅——第二站:对象和数组

    一觉睡到中午,本来准备起来洗洗继续睡,不过想想没辙,还得继续这个系列,走过变量的第一站,第二站我们再来看看对象和数组. 一:对象   说起对象,我们不自然就想起了面向对象中自封装的一个类,同样JS中也 ...

  3. 初学Mahout测试kmeans算法

    预备工作: 启动hadoop集群 准备数据 Synthetic_control.data数据集下载地址http://archive.ics.uci.edu/ml/databases/synthetic ...

  4. sql server 常见错误代码15000 - 15999含义解析

    错误 15000 - 15999 SQL Server 2008 R2 其他版本 错误 严重性 是否记录事件 说明(消息正文) 15001 16 否 对象 '%ls' 不存在或不是此操作的有效对象. ...

  5. 使用国内 maven 镜像 代替国外 mirror

    使用maven的都知道国外的maven下载一个是比较慢,一个是因为被墙,一些jar包无法下载,非常老火. 比如出现类似下面的错误: Unknown host repo.maven.apache.org ...

  6. 一致性算法Paxos详解

    分布式系统除了能提升整个系统的性能外还有一个重要的特性就是提高系统的可靠性,可靠性指的是当分布式系统中一台或N台机器宕掉后都不会导致系统不可用,分布式系统是state machine replicat ...

  7. TFS - 使用微软测试管理器实现跨团队项目的测试用例管理

    在团队项目之间实现测试用例和测试计划的共享,是很多客户关注的问题.尤其在开发产品+服务的团队中,对测试用例的共享要求比较高.下面就如何在Team Foundation Server中如何实现团队项目之 ...

  8. Windows Azure 虚拟机备份

    如果我们要在Windows Azure的虚拟机上进行一些“重要且高危”的操作,我们通常会想到使用快照或者备份功能.但是在Windows Azure上是没有虚拟机快照功能的,尽管我们可以对虚拟机的磁盘文 ...

  9. 准备使用 Office 365 中国版--购买

    Office 365中国版支持两种购买方式,Web Direct(在线购买)和CSP(代理商购买).如果客户的企业规模不大(几十个用户,小于100用户)或者是个人/家庭购买,可以直接选择在线购买方式. ...

  10. [转]C#编程总结(三)线程同步

    本文转自:http://www.cnblogs.com/yank/p/3227324.html 在应用程序中使用多个线程的一个好处是每个线程都可以异步执行.对于 Windows 应用程序,耗时的任务可 ...