尝试设计一套特质,灵活的改动整数队列。队列有两种操作:put把整数放入队列,get从尾部取出它们。队列是先进先出的,get应该依照入队列的顺序取数据。提示:可以用mutable.ArrayBuffer 模拟队列在报告中体现出类的线性化特性,要求扩展类实现如下三个功能1.Doubling 把放到队列中的数字翻倍;2.Incrementing 把放到队列的数据增加1;3.过滤掉队列中的负数

 abstract class Queue2 {
println("查看调用顺序Queue")
def get:Int
def put(num:Int)
}
trait Doubling extends Queue2 {
println("查看调用顺序Doubling")
abstract override def put(x: Int) { super.put(2*x) }
}
trait Incrementing extends Queue2 {
println("查看调用顺序Incrementing")
abstract override def put(x: Int) { super.put(x+1) }
}
trait Filtering extends Queue2 {
println("查看调用顺序Filtering")
abstract override def put(x: Int){
if(x >= 0) super.put(x)
}
}
class NewQueue extends Queue2{
println("查看调用顺序NewQueue")
private val numArrayBuffer = new ArrayBuffer[Int]
def get() = numArrayBuffer.remove(0)
def put(x: Int) = {
numArrayBuffer += x
}
}
object test5{
def main(args: Array[String]): Unit = {
val queue = new NewQueue with Doubling
queue.put(1)
println(queue.get()) val queue2 = new NewQueue with Doubling with Incrementing
queue2.put(10)
println(queue2.get()) }
}

  首先我们知道特质构造器的调用顺序是:

  1.调用超类的构造器;

  2.特质构造器在超类构造器之后、类构造器之前执行;

  3.特质由左到右被构造;

  4.每个特质当中,父特质先被构造;

  5.如果多个特质共有一个父特质,父特质不会被重复构造

  6.所有特质被构造完毕,子类被构造。

  混入的顺序很重要,越靠近右侧的特质越先起作用。当你调用带混入的类的方法时,最右侧特质的方法首先被调用。如果那个方法调用了super,它调用其左侧特质的方法,以此类推。

这里很神奇的一点是,输入10,输出居然是22而不是21。貌似是Incrementing的put首先被调用,然后Doubing的put第二个被调用。但为什么在显示语句中,我们发现先显示的是“查看调用顺序Doubling”呢?

  我们来看看类的线性化的含义:

  特质是一种继承多个类似于类的结构的方式,但是它与多重继承有很重要的区别。其中一个尤为重要:super的解释。

  对于多重继承来说,super调用导致的方法调用可以在调用发生的地方明确决定;对于特质来说,方法调用是由类和混入到类的特质的线性化(linearization)所决定的。这种差别使得上面的特质的堆叠成为可能。

  在多重继承的语言中,调用相同的方法,编译规则会决定哪个超类最终胜出,而调用该超类的指定方法。

  而在Scala中,当你使用new实例化一个类的时候,Scala把这个类和所有它继承的类还有他的特质以线性的次序放在一起。然后,当你在其中的一个类中调用super,被调用的方法就是方法链的下一节。除了最后一个调用super之外的方法,其净结果就是可堆叠的行为。

  所以,在这里我们看到调用顺序的确是先Doubling后Incrementing,但是在线性的过程中,先执行的是最后一层,即越靠近右侧的特质越先起作用。先+1,再*2,最后put。

  举例:

 class A{
println("查看调用顺序A")
def m(s:String) = println(s"A($s)")
}
trait B extends A{
println("查看调用顺序B")
override def m(s:String) = super.m(s"B($s)")
}
trait C extends A{
println("查看调用顺序C")
override def m(s:String) = super.m(s"C($s)")
}
trait D extends A{
println("查看调用顺序D")
override def m(s:String) = super.m(s"D($s)")
}
trait E extends C{
println("查看调用顺序E")
override def m(s:String) = super.m(s"E($s)")
}
trait F extends C{
println("查看调用顺序F")
override def m(s:String) = super.m(s"F($s)")
}
class G extends D with E with F with B{
println("查看调用顺序G")
override def m(s:String) = super.m(s"G($s)")
}
object t{
def main(args: Array[String]): Unit = {
val x = new G
x.m("")
}
}

  这段代码最后的输出结果是:

  为什么呢?

  G extends D with E with F with B

  D extends A

  E extends C,C extends A

  F extends C,C extends A

  B extends A

  1.从左往右,选择离G的trait最近的进行放置在左边,他的父类放在右边

  2.依次将剩下的trait的也从左边开始放置,如果其父类已经出现在右边,则跳过

  3.在最右加入AnyRef和Any,完成构建

  1.GDA

  2.GECDA

  3.GFECDA

  4.GBFECDA

 

Scala入门3(特质线性化)的更多相关文章

  1. Scala学习十——特质

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

  2. Scala入门学习笔记三--数组使用

    前言 本篇主要讲Scala的Array.BufferArray.List,更多教程请参考:Scala教程 本篇知识点概括 若长度固定则使用Array,若长度可能有 变化则使用ArrayBuffer 提 ...

  3. Scala入门 【1】

    Scala入门 [1] 转载请注明出处:http://www.cnblogs.com/BYRans/ 1 基础 val定义的为常量,var为变量 val name:Type = ***,变量名后加冒号 ...

  4. Scala入门(1)Linux下Scala(2.12.1)安装

    Scala入门(1)Linux下Scala(2.12.1)安装 一.文件准备 1.1 文件名称 scala-2.12.1.tgz 1.2 下载地址 http://www.scala-lang.org/ ...

  5. scala 入门Eclipse环境搭建

    scala 入门Eclipse环境搭建及第一个入门经典程序HelloWorld IDE选择并下载: scala for eclipse 下载: http://scala-ide.org/downloa ...

  6. Scala 入门详解

    Scala 入门详解 基本语法 Scala 与 Java 的最大区别是:Scala 语句末尾的分号 ; 是可选的 Scala 程序是对象的集合,通过调用彼此的方法来实现消息传递.类,对象,方法,实例变 ...

  7. idea创建Scala入门HelloWorld

    Scala开发环境的搭建 首先到Scala官网下载Scala网址为 https://www.scala-lang.org/download/ 找到下图所示位置:选择相对应的版本的Scala进行下载,这 ...

  8. IntelliJ中的Scala入门

    IntelliJ IDE中的Scala入门 创建项目 打开IntelliJ并单击File => New => Project 在左侧面板中,选择Scala.在右侧面板中,选择IDEA. 将 ...

  9. Scala入门到精通

    原文出自于: http://my.csdn.net/lovehuangjiaju 感谢! 也感谢,http://m.blog.csdn.net/article/details?id=52233484 ...

  10. scala 入门Eclipse环境搭建及第一个入门经典程序HelloWorld

    scala 入门Eclipse环境搭建及第一个入门经典程序HelloWorld 学习了: http://blog.csdn.net/wangmuming/article/details/3407911 ...

随机推荐

  1. 2015/12/14 Python网络编程,TCP/IP客户端和服务器初探

    一直不是很清楚服务器的定义,对于什么是服务器/客户端架构也只有一个模糊的感觉.最近开始学习,才明白一些什么服务器和客户端的关系. 所谓的服务器,就是提供服务的东西,它是一个硬件或者软件,可以向一个或者 ...

  2. HttpContext.Current為空匯總

    1. async異步模式下為空 解决办法: <httpRuntime targetFramework="4.5" /> 或者: In your appSettings, ...

  3. Anaconda+django写出第一个web app(一)

    在安装好Anaconda和django之后,我们就可以开始创建自己的第一个Web app,那么首先创建一个空文件夹,之后创建的文件都在这个文件夹内. 启动命令行进入此文件夹内,可以先通过如下命令查看一 ...

  4. js实现数组、对象深度克隆的两种办法

    1.深度克隆的原理 JS中的深度克隆,指的是原对象改变了,克隆出来的新对象也不会改变,原对象与新对象是完全独立的关系. 实现深度克隆的原理得从对象是一种引用类型说起 众所周知,对象是一种引用类型,对象 ...

  5. PyTorch快速入门教程七(RNN做自然语言处理)

    以下内容均来自: https://ptorch.com/news/11.html word embedding也叫做word2vec简单来说就是语料中每一个单词对应的其相应的词向量,目前训练词向量的方 ...

  6. linux键盘input_event浅析【转】

    转自:http://blog.csdn.net/tdstds/article/details/18710965 input_event(mxckbd_dev, EV_KEY, mxckpd_keyco ...

  7. MySQL主从复制-指定数据库复制

    在/etc/my.cnf添加需要进行同步的数据库信息 #需要进行同步的数据库 #replicate-do-db=custmgr #replicate-do-db=sdata #replicate-ig ...

  8. maven package exec 及 maven 配置文件详解

    maven package test包下执行test 的配置文件 生成target目录,编译.测试代码,生成测试报告,生成jar/war文件 maven 配置文件详解 http://blog.csdn ...

  9. 洛谷P1938 找工就业

    传送门啦 这个题本质就是跑一边最长路,重点就是在怎么建图上. 我们可以把点权放到边权上面,即将每一个边的终点点权当做这个边的边权,这个题里就是将工钱 $ d $ 当做边权. 如果这一条边需要坐飞机才能 ...

  10. Sublime Text 3 web 开发常用配置

    前沿 Sublime Text 是一个代码编辑器(Sublime Text 2是收费软件,但可以无限期试用),也是HTML和散文先进的文本编辑器.Sublime Text是由程序员Jon Skinne ...