特质的再说明|学习笔记

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

开发者学堂课程【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 两个接口。

相关文章
|
7月前
|
编译器 C++
C++-带你走进多态(1)
C++-带你走进多态(1)
38 0
|
4月前
|
Java 开发者
那些年,我们一同踏入Java编程的大门,多态,这个充满魔法的名字,曾无数次点亮我们探索面向对象编程的热情。
那些年,我们一同踏入Java编程的大门,多态,这个充满魔法的名字,曾无数次点亮我们探索面向对象编程的热情。
49 5
|
6月前
|
Java
Java面向对象编程新篇章:多态,你准备好了吗?
【6月更文挑战第17天】Java的多态性是面向对象编程的核心,它允许通过统一的接口处理不同类型的对象。例如,在一个虚拟宠物游戏中,抽象类`Pet`定义了`speak()`方法,猫、狗和鹦鹉等子类各自重写此方法以实现独特叫声。在`main`方法中,使用`Pet`类型的引用创建子类对象并调用`speak()`,多态机制确保调用实际对象的方法,实现代码的灵活性和可扩展性。通过多态,我们能以更低的耦合度和更高的复用性编写更优雅的代码。
39 3
|
7月前
|
编译器 C++
c++的学习之路:22、多态(1)
c++的学习之路:22、多态(1)
45 0
c++的学习之路:22、多态(1)
|
7月前
|
编译器 C++
c++的学习之路:23、多态(2)
c++的学习之路:23、多态(2)
57 0
|
7月前
|
设计模式 缓存 安全
感受单例模式的力量与神秘:掌握编程的王牌技巧
在软件开发的赛场上,单例模式以其独特的魅力长期占据着重要的地位。作为设计模式中的一员,它在整个软件工程的棋盘上扮演着关键性角色。本文将带你深入探索单例模式的神秘面纱,从历史渊源到现代应用,从基础实现到高级技巧,经过戏剧性的转折和层层推进,我们将一步步揭开这一模式背后的秘密。文章串起时间的线索,带你重回单例模式的起源,理解它在软件工程历史中的地位。经过时间的流逝,单例模式不仅保持了其原有的魅力,而且随着新的编程语言和技术的发展,还展示出了新的活力和应用场景。
69 1
|
7月前
|
存储 编译器 C语言
『C++成长记』类和对象
『C++成长记』类和对象
|
程序员 容器
程序员基本素养和特质
程序员基本素养和特质
|
C语言
C素养提升-函数专题
在c语言中,函数是一个完成特定功能的代码模块,其程序代码独立,通常要求有返回值,也可以是空值。
76 0
|
自然语言处理 JavaScript 程序员
掌握闭包,夯实基本功
闭包在程序中无处不在,通俗来讲闭包就是一个函数对其周围状态的引用并捆绑在一起的一种组合,你也可以理解成一个函数被引用包围或者是一个内部函数能够访问外部函数的作用域
123 0
掌握闭包,夯实基本功