特质的再说明|学习笔记

简介: 快速学习特质的再说明。

开发者学堂课程【Scala 核心编程-基础:特质的再说明】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/609/detail/8991


特质的再说明

 

一、特质 trait 的再说明

1、Scala 提供了特质(trait),特质可以同时拥有抽象方法和具体方法,一个类可以实现继承多个特质。

(1)思考:特质有抽象方法,又有具体方法,那么特质在底层具体对应什么?它们之间又是怎么调用的?这涉及到特质底层调用原理。

在 mytrait 目录下新建 Create New Scala Class,Name 为 TraitDemo03,Kind 为 Object。打开编辑:

package com.atguigu.chapter08.mytrait

object TraitDemo03 {

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

println("~~~~")

//创建 sheep

val sheep = new Sheep

sheep.sayHi()

sheep.sayHello()

}

}

trait Trait03 {

//抽象方法

def sayHi()

//实现普通方法

def sayHello(): Unit = {

println("say Hel1o~~" )

}

}

class Sheep extends Trait03 {

override def sayHi(): Unit = {

println("小羊say hi~~")

}

}

先写 trait03,然后写抽象方法,再写实现普通方法。再写一个类继承 trait03。这里,看到 Sheep 下出现红色波浪线,报错,因为抽象方法还没有实现。点击 Sheep,选择 Implement methods 实现方法,在弹出的 Select Members to Implement 窗口选择s ayHi0: Unit 点击 OK。然后输出小羊 say hi~~。然后创建一只小羊对象,对 sheep 进行调用。运行结果如下:

~~~~

小羊 say hi~~

say Hello~~

(2)探讨话题:trait Trait03发生了什么?class Sheep extends Trait03发生了什么?

有普通方法和没有普通方法之间原理有变化。

① 没有普通方法时

先注销普通方法 def sayHello(),看运行结果:

~~~~

小羊say hi~~

打开 Java Decompiler,点击左上角文件图标,在 atguigu 目文件录下的 chapter08文件中 mytrait 文件里,找到 Trait03.class,这时,这里只有 Trait03。打开。在 Java Decompiler - Trait03.class 源码中,看到

public abstract interface Trait03

{

public abstract void sayHi ():

}

这里有一个抽象方法 sayHi (),仅是一个接口。

思考:在 TraitDemo03.scala 中的程序 class Sheep extends Trait03里,底层 Sheep 类是怎么和 Trait03关联起来的?

打开 Sheep.scala 的源码,

public class Sheep

implements Trait03

{

public void sayHi ()

{

Predef..MODULE$.print1n("小羊say hi~~");

}

}

看到这里和 Java 的原理一样。即,当 Trait 里只有抽象方法时,与 Java 的机制完全一样。

②  有普通方法时

打开普通方法 def sayHello()。可以发现,Java 中不能把实现的方法占为己用。显然,不可以把实现的方法放在接口。实现方法放到机器里是不可以的。

当一个 Trait 有抽象方法和非抽象方法时。一个 Trait 会在底层对应两个类。包对象、伴生对象、和 trait 都是一样的原理。第一个类 Trait03.class 实际上就是接口。还对应 Trait03$class.class,会生成 Trait03$class 的抽象类。抽象类可以实现方法。这时,trait 就有两个,一个是接口,一个抽象类。

把分开过后,class Sheep extends Trait03会变成什么?

trait 有接口和抽象类时,class Sheep extends Trait03在底层会直接实现接口,Employment实现trait Trait03接口。但是,这里面的方法直接用 Trait03$class 里的方法所以当在 Sheep 这个类中要使用 Treat03实现的方法,就直接通过 Trait03$class 抽象类来调

编译运行后,重新打开 jd-gui.exe,在 Java Decompiler 窗口点击文件图标,在 mytrait 目录下看到两个 Trait03,一个是 Trait03$class.class,另一个是 Trait03.class。

Trait03.class 是接口。打开,

public abstract interface Trait03

{

pub1ic abstract void sayHi () ;

public abstract void sayHello() ;

}

看到 Trait03.class 是接口。有两个方法 sayHi ()sayHello()

sayHello()虽然是抽象的,但是它把真正实现的方法放在 Trait03$class 中。

打开 Trait03$class.class

public abstract class Trait03$class

{

public static void sayHe11o(Trait03 $this)

{

Predef..MODULE$.print1n("say Hello~~");

}

public static void $init$ (Trait03 $this)

{

}

}

看到 sayHe11o(Trait03 $this)方法。sayHe11o()只是在接口里声明了方法,但真正实现方法还是在 Trait03$class中。

打开 Shepp.class 源码,

public class Sheep

implements Trait03

{

public void sayHello()

{

Trait03.class.sayHe11o(this) ;

}

public void sayHi() { Predef..MODULE$.print1n("小羊say hi~~"); }

public Sheep()

{

Trait03.clasg.$init$(this) :

}

}

看到只实现 Trait03接口。实现 Trait03接口,就会把 sayHello() sayHi()方法都实现。

sayHi() 是 Sheep 自己实现的。sayHello()则是做了语法调用。Sheep 把 Trait03接口里的 sayHello()写过来后,直接调用了 Trait03.class 的反编译拿到 sayHe11o(this) 来调用。

(3)示意图理解

图片6.png

示意图解释说明如下:

图片5.png

图中是一段 trait 特质代码。如果没有普通方法程序段,那就只是一个接口。这里有普通方法,会对应生成两个内容。

一个是生成所谓纯的接口,如下图中源程序段;

图片4.png

另一个是生成抽象类,把实现非抽象类的方法放到抽象类里面。如下图:

图片3.png

一个 trait 对应两个文件,Trait03.class 和 Trait03$class.dass

这个方法是怎么使用的?在底层调用。

图片2.png

小羊 sayhi~~代码段对应生成 Sheep.class 文件。

在 Sheep.class 中实现 Trait03的两个方法,sayHi ()sayHello()

图片1.png

sayHello()做包装,在实现的时候,通过名字与 Trait03$class.dass 文件进行关联。

Trait03.class.sayHe11o(this) 直接使用了抽象类中的 public static void sayHe11o(Trait03 $this)写的 sayHello。

自己写的小羊 sayhi~~ 会直接对应到 Sheep.class中。

总之,Trait 就是接口和抽象类的组合体。

2、特质中没有实现的方法就是抽象方法。类通过 extends 继承特质,通过 with 可以继承多个特质

3、所有的 java 接口都可以当做 Scala 特质使用

案例:演示一个类怎么继承多个特质的语法

trait Logger {

def log(msg: String)

}

class Console extends Logger with Cloneable with Serializable{

def log(msg: String) {

println(msg)

}

}

Console 类实现第一个特质 Logger,又直接使用 Java 中的 Cloneable Serializable 两个接口。

相关文章
|
前端开发
|
NoSQL 测试技术 Scala
java.lang.RuntimeException: Can‘t start redis server. Check logs for details.
java.lang.RuntimeException: Can‘t start redis server. Check logs for details.
260 1
|
监控 安全 网络安全
网络安全应急响应常用工具介绍
在网络安全应急响应中可使用的工具很多,我将我认知的以下部分常用工具分享给大家
网络安全应急响应常用工具介绍
|
存储 安全 算法
智能终端信息安全概念(五):硬件安全技术—加密芯片
智能终端信息安全概念(五):硬件安全技术—加密芯片
509 0
|
easyexcel Java
EasyExcel实现Excel文件多sheet导入导出
EasyExcel实现Excel文件多sheet导入导出
1847 0
|
网络协议 关系型数据库 MySQL
解决本地计算机上的MySQL80服务启动后停止。某些服务在未由其他服务或程序使用时将自动停止
解决本地计算机上的MySQL80服务启动后停止。某些服务在未由其他服务或程序使用时将自动停止
6952 1
解决本地计算机上的MySQL80服务启动后停止。某些服务在未由其他服务或程序使用时将自动停止
|
分布式计算 资源调度 监控