Scala特证/特质【6.7 特质(Trait)】

news2024/11/27 12:36:40

Scala特证/特质【6.7 特质(Trait)】

    • 6.7 特质(Trait)
    • Java 的接口
      • 接口的作用
      • 抽象类的作用
    • 6.7.1 特质声明
    • 6.7.2 特质基本语法
    • 6.7.3 特质叠加
    • 6.7.4 特质叠加执行顺序
    • 6.7.5 特质自身类型
    • 6.7.6 特质和抽象类的区别

(任意内容)

此处输入任意想输入的内容

6.7 特质(Trait)

  • Scala 语言中,采用特质 trait(特征)来代替接口的概念 ,也就是说,多个类具有相同的特质(特征)时,就可以将这个特质(特征)独立出来,采用关键字 trait 声明。
  • Scala 中的 trait 中即可以有抽象属性和方法,也可以有具体的属性和方法,一个类可
    以混入(mixin)多个特质。这种感觉类似于 Java 中的抽象类。
  • Scala 引入 trait 特征,第一可以替代 Java 的接口,第二个也是对单继承机制的一种
    补充。

Java 的接口

Java中的接口(Interface)是一种抽象类型,用于定义类应该具有的行为。接口可以看作是一组方法的集合,但是接口不能包含实现代码,只能定义方法的签名。类可以实现一个或多个接口,并提供接口中定义的方法的具体实现。

接口的定义使用interface关键字,语法如下:

public interface MyInterface {
    // 抽象方法
    void abstractMethod();

    // 默认方法
    default void defaultMethod() {
        // 方法实现
    }

    // 静态方法
    static void staticMethod() {
        // 方法实现
    }
}

在Java中,类通过implements关键字来实现接口:

public class MyClass implements MyInterface {
    // 实现接口中的抽象方法
    public void abstractMethod() {
        // 方法实现
    }
}

一个类可以实现多个接口,通过逗号分隔:

public class MyClass implements Interface1, Interface2 {
    // 实现接口中的抽象方法
    // ...
}

接口的作用

接口中的方法可以是抽象方法、默认方法(默认实现)和静态方法。抽象方法由实现类提供具体实现,而默认方法和静态方法可以直接在接口中提供实现代码。默认方法可以被实现类重写,静态方法则不能。

接口在Java中用于实现多态性和代码复用,它提供了一种契约机制,用于定义类的行为规范。通过实现接口,可以在不同的类中共享一组方法,提高代码的灵活性和可扩展性。接口在Java中被广泛应用于各种编程场景,例如回调机制、事件处理、依赖注入等。

接口在编程中起到了以下几个重要的作用:

  1. 定义契约:接口定义了一组方法的契约或规范,指定了类应该具备的行为。通过接口,可以明确地定义类应该提供哪些方法,以及这些方法应该如何被实现。接口提供了一种契约机制,帮助程序员在不同的类之间建立统一的行为规范。

  2. 实现多态:接口是实现多态性的关键。通过接口,可以实现类的多态性,使得不同的对象可以以统一的方式对待。通过接口的引用,可以引用不同实现类的对象,并调用它们实现的接口方法,实现了代码的灵活性和可扩展性。

  3. 代码复用:接口提供了一种代码复用的机制。通过接口,可以定义一组方法,并在多个类中实现这些方法。其他类可以实现相同的接口,从而复用接口中定义的方法。这种方式可以减少代码的重复编写,提高代码的可维护性和可复用性。

  4. 解耦和组件化:接口可以帮助解耦和实现组件化。通过接口,不同的模块或组件之间可以通过接口进行通信,而不需要了解具体的实现细节。这样可以降低模块之间的耦合度,提高系统的灵活性和可扩展性。

  5. 定义规范:接口可以被用作定义规范的工具。通过接口,可以定义一组方法和常量,并约束其他类去实现这些方法或使用这些常量。这样可以保证代码的一致性和可靠性。

总而言之,接口在编程中具有重要的作用,它定义了类的行为规范、实现多态性、实现代码复用、解耦和组件化,以及定义规范等。通过接口,可以提高代码的灵活性、可维护性和可扩展性,使得程序更加可靠和可重用。

抽象类的作用

抽象类在面向对象编程中起着重要的作用,它具有以下几个主要作用:

  1. 定义通用行为:抽象类可以定义一组通用的方法和属性,这些方法和属性可以被其子类继承和重写。抽象类可以提供一种通用的行为规范,让子类按照自己的需求进行具体实现。

  2. 实现代码复用:抽象类可以包含一些通用的方法的实现,这样子类就可以直接继承这些方法的实现,避免了代码的重复编写。通过抽象类的继承关系,可以实现代码的复用,提高代码的可维护性和可复用性。

  3. 实现多态性:抽象类可以作为父类,被其子类进行继承和扩展。通过抽象类的引用,可以引用不同子类的对象,实现多态性。这样可以在运行时根据实际对象的类型调用相应的方法,实现灵活的代码结构。

  4. 定义抽象方法:抽象类可以定义抽象方法,这些方法只有方法的声明而没有具体的实现。抽象方法必须由子类进行具体实现,通过抽象方法的定义,可以强制子类去实现特定的行为。

  5. 作为模板类:抽象类可以作为模板类,定义一些通用的方法和属性,提供给子类进行继承和使用。子类可以通过继承抽象类,并根据自己的需求进行具体实现和扩展,从而达到代码复用和模块化的目的。

总而言之,抽象类在面向对象编程中具有重要作用,它可以定义通用行为、实现代码复用、实现多态性、定义抽象方法和作为模板类。通过抽象类,可以提高代码的可维护性、可复用性和可扩展性,使得程序设计更加灵活和可靠。

6.7.1 特质声明

1)基本语法

trait 特质名 {
	trait 主体
}

2)案例实操

trait PersonTrait {
	 // 声明属性
	 var name:String = _
	 // 声明方法
	 def eat():Unit={
	 }
	 // 抽象属性
	 var age:Int
	 
	 // 抽象方法
	 def say():Unit
}
通过查看字节码,可以看到特质=抽象类+接口

6.7.2 特质基本语法

  • 一个类具有某种特质(特征),就意味着这个类满足了这个特质(特征)的所有要素,所以在使用时,也采用了 extends 关键字,如果有多个特质或存在父类,那么需要采用 with关键字连接。
    在这里插入图片描述
    2)说明
    (1)类和特质的关系:使用继承的关系。
    (2)当一个类去继承特质时,第一个连接词是 extends,后面是 with。
    (3)如果一个类在同时继承特质和父类时,应当把父类写在 extends 后。

3)案例实操
(1)特质可以同时拥有抽象方法和具体方法
(2)一个类可以混入(mixin)多个特质
(3)所有的 Java 接口都可以当做 Scala 特质使用
(4)动态混入:可灵活的扩展类的功能

  • (4.1)动态混入:创建对象时混入 trait,而无需使类混入该 trait
  • (4.2)如果混入的 trait 中有未实现的方法,则需要实现
trait PersonTrait {
	 //(1)特质可以同时拥有抽象方法和具体方法
	 // 声明属性
	 var name: String = _
	 // 抽象属性
	 var age: Int
 // 声明方法
 def eat(): Unit = {
 	println("eat")
 }
 // 抽象方法
 def say(): Unit
	}
trait SexTrait {
	 var sex: String
}
//(2)一个类可以实现/继承多个特质
//(3)所有的 Java 接口都可以当做 Scala 特质使用
class Teacher extends PersonTrait with java.io.Serializable {
	 override def say(): Unit = {
 		println("say")
	 }
	 override var age: Int = _
	}
object TestTrait {
	 def main(args: Array[String]): Unit = {
	 val teacher = new Teacher
	 teacher.say()
	 teacher.eat()
	 //(4)动态混入:可灵活的扩展类的功能
	 val t2 = new Teacher with SexTrait {
	 override var sex: String = "男"
 }
 //调用混入 trait 的属性
	 println(t2.sex)
   }
}

6.7.3 特质叠加

  • 由于一个类可以混入(mixin)多个 trait,且 trait 中可以有具体的属性和方法,若混入的特质中具有相同的方法(方法名,参数列表,返回值均相同),必然会出现继承冲突问题。

冲突分为以下两种:

  • 第一种,一个类(Sub)混入的两个 trait(TraitA,TraitB)中具有相同的具体方法,且
    两个 trait 之间没有任何关系,解决这类冲突问题,直接在类(Sub)中重写冲突方法。
    在这里插入图片描述

  • 第二种,一个类(Sub)混入的两个 trait(TraitA,TraitB)中具有相同的具体方法,且
    两个 trait 继承自相同的 trait(TraitC),及所谓的“钻石问题”,解决这类冲突问题,Scala
    采用了特质叠加的策略。
    在这里插入图片描述
    所谓的特质叠加,就是将混入的多个 trait 中的冲突方法叠加起来,案例如下,

trait Ball {
 def describe(): String = {
	 "ball"
 	}
}
trait Color extends Ball {
	 override def describe(): String = {
 		"blue-" + super.describe()
 }
}
trait Category extends Ball {
  override def describe(): String = {
	 "foot-" + super.describe()
	 }
}
class MyBall extends Category with Color {
  override def describe(): String = {
	 "my ball is a " + super.describe()
 }
}
object TestTrait {
	 def main(args: Array[String]): Unit = {
		 println(new MyBall().describe())
	 }
}

结果如下:

在这里插入图片描述

6.7.4 特质叠加执行顺序

思考: 上述案例中的 super.describe()调用的是父 trait 中的方法吗?

  • 当一个类混入多个特质的时候,scala 会对所有的特质及其父特质按照一定的顺序进行
    排序,而此案例中的 super.describe()调用的实际上是排好序后的下一个特质中的 describe()
    方法。,排序规则如下:
    在这里插入图片描述

结论:
在这里插入图片描述
在这里插入图片描述

6.7.5 特质自身类型

1)说明

  • 自身类型可实现依赖注入的功能。

2)案例实操

class User(val name: String, val age: Int)
trait Dao {
 def insert(user: User) = {
 println("insert into database :" + user.name)
 }
}
trait APP {
 _: Dao =>
 def login(user: User): Unit = {
 println("login :" + user.name)
 insert(user)
 }
}
object MyApp extends APP with Dao {
 def main(args: Array[String]): Unit = {
 login(new User("bobo", 11))
 }
}

6.7.6 特质和抽象类的区别

1.优先使用特质。一个类扩展多个特质是很方便的,但却只能扩展一个抽象类。
2.如果你需要构造函数参数,使用抽象类。因为抽象类可以定义带参数的构造函数,
而特质不行(有无参构造)。
3.特质(Trait)和抽象类(Abstract Class)是Scala语言中两种常见的代码组织方式,它们有一些区别和特点。

  1. 继承关系:特质和抽象类都可以被其他类继承。但是,一个类只能继承一个抽象类,而可以同时继承多个特质(多重继承)。

  2. 单继承 vs. 多重混入:由于Scala只支持单继承,所以通过继承一个抽象类,子类只能继承一个父类的特性。而通过混入特质,可以将多个特质的功能组合到一个类中,实现多重混入。

  3. 构造器:抽象类可以有构造器,而特质不能直接拥有构造器。特质可以通过在类中混入时传递参数的方式来影响类的行为。

  4. 抽象方法和具体方法:抽象类可以包含抽象方法和具体方法。抽象方法只有声明而没有具体实现,由子类实现。而特质可以包含抽象方法和具体方法,特质中的方法默认是抽象的,但也可以提供默认的实现。

  5. 实例化:抽象类不能直接实例化,只能被继承。而特质也不能直接实例化,但可以通过混入到具体类中来影响类的行为。

  6. 使用场景:抽象类通常用于定义一些共性的行为和状态,被子类继承和扩展。特质通常用于定义一些可复用的代码片段,可以被多个类混入,实现代码的复用和模块化。

总而言之,特质和抽象类在Scala中有不同的用途和特点。抽象类用于定义类的继承关系和共性行为,而特质用于实现代码的复用和模块化,可以多重混入到类中。根据具体的需求,可以选择合适的方式来组织代码结构。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/720184.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Lua学习笔记:面向对象的实现

前言 本篇在讲什么 Lua中的面向对象的实现 本篇适合什么 适合初学Lua的小白 本篇需要什么 对Lua语法有简单认知 依赖Sublime Text编辑器 本篇的特色 具有全流程的图文教学 重实践,轻理论,快速上手 提供全流程的源码内容 ★提高阅读体验★ &…

MySQL数据库基础(三):多表查询,子查询,开窗函数

十一、多表查询(重点、难点) 表与表之间的关系 在SQL语句中,数据表与数据表之间,如果存在关系,一般一共有3种情况: ① 一对一关系(高级) 比如有A、B两张表,A表中的每一…

多肽试剂:143120-27-8,Cyclo(-D-Tyr-Arg-Gly-Asp-Cys(carboxymethyl)-OH) sulfoxide

试剂基团反应特点(Reagent group reaction characteristics): 环肽试剂Cyclo(-D-Tyr-Arg-Gly-Asp-Cys(carboxymethyl)-OH) sulfoxide,陕西新研博美生物科技有限公司多肽合成、定制多肽、同位素标记肽、人工胰岛素、磷酸肽、生物素…

Python split()函数使用详解,Python分割字符串

「作者主页」:士别三日wyx 「作者简介」:CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」:小白零基础《Python入门到精通》 split 1、不指定分隔符2、分隔符的类型3、指定分隔次数4、分隔的结果 split() 可…

你真的不想知道怎么用ai绘画图片生成图片吗?

亲爱的二次元迷们,你是否曾经梦想过能够画出自己心中的二次元角色,让他们跃然纸上、生动活泼地展现在世人面前?但是,面对空白的画板和一支笔,我们有时会感到无从下手,毫无艺术细胞可言。不要失望&#xff0…

Dlib —— 对视频流进行人脸识别(附C++部分源码、完整源码下载)

照片效果 视频效果 注意:Dlib检测人脸在Release版耗时与CPU有关,本人I7 10代约100ms左右,这里本人将人脸检测用Yolov5对人脸简单抠图训练后 使用yolov5推理检测人脸,之后将检测到的人脸输入给Dlib做特征,发现人脸特征部分耗时也较…

基础实验篇 | uORB消息读写与自定义实验(一)

导读 uORB是PX4/Pixhawk系统中非常重要且关键的模块之一,是用于无人机模块间通信的协议机制。本篇将详细介绍uORB并详细拆解uORB消息读写与自定义实验(一)。 基础实验篇 | uORB消息读写与自定义实验(一) ect Request Broker,微对…

7、动手学深度学习——卷积神经网络:基础部件+LeNet

1、图像卷积 1. 互相关运算 严格来说,卷积层是个错误的叫法,因为它所表达的运算其实是互相关运算(cross-correlation),而不是卷积运算。在卷积层中,输入张量和核张量通过(互相关运算)产生输出张量。 首先…

python 中禁用 SettingWithCopyWarning

最近代码中出现了这个warn,但是我确信我已经把所有的df赋值都改成loc了,依旧会出现,只有把这个warn禁了。 import pandas as pd import warnings# 禁用 SettingWithCopyWarning 警告 warnings.filterwarnings("ignore", categorypd…

闲人闲谈PS之四十三——标准程序的陷阱

惯例闲话:7月,闲人家乡的水蜜桃成熟了,闲人很喜欢吃桃子,可惜经常出门在外,经常错过了水果最好的季节,这次委托家人邮寄了几箱,果然还是家乡的桃子好吃。回顾这几年,错过了不仅仅是水…

数据库sql 根据身份证计算年龄段mysql、oracle

数据库sql根据身份证计算年龄段 mysql: SELECTage,count(*) numFROM(SELECTCASEWHEN TIMESTAMPDIFF(YEAR,DATE(substring(id_card,7,8)),CURDATE())<35 THEN 35岁以下WHEN TIMESTAMPDIFF(YEAR,DATE(substring(id_card,7,8)),CURDATE()) > 35AND TIMESTAMPDIFF(YEAR,DATE…

deque容器语法

文章目录 deque容器deque容器基本概念功能&#xff1a;deque 的实现细节deque与vector底层区别&#xff1a; deque构造函数功能描述&#xff1a;函数原型&#xff1a; deque元素访问deque赋值操作功能描述&#xff1a;函数原型&#xff1a; deque大小操作功能描述&#xff1a;函…

哪些期货公司招居间人,期货居间人的红利期时代已过,该何去何从

2021年9月10日&#xff0c;中国期货业协会发布了关于发布《期货公司居间人管理办法 (试行)》的通知&#xff0c;《期货公司居间人管理办法(试行)》正式出台。 根据通知&#xff0c;期货公司仅能与经有关金融监管部门批准设立的证券公司等金融机构开展居间合作。现在的法人居间绝…

【stable-diffuision-webui】controlnet制作动漫二维码(丐版)

主要参考 原作者的博文&#xff1a;AI生成可扫码图像 — 新 ControlNet 模型展示 光照生成模型C站说明&#xff1a;https://civitai.com/models/80536/lighting-based-picture-control-controlnet 扩展阅读&#xff1a;https://aigc.ioclab.com/sd-showcase/light_controlnet.…

Sentieon | 每周文献-Agrigenomics-第四期

农业系列文章-1 标题&#xff08;英文&#xff09;&#xff1a;Genomic footprints of sorghum domestication and breeding selection for multiple end uses标题&#xff08;中文&#xff09;&#xff1a;高粱驯化的基因组足迹和多种最终用途的育种选择发表期刊&#xff1a;《…

vue3中使用jsx

一、使用vue-cli创建的项目中使用jsx语法 安装Vue 3&#xff1a;使用Vue CLI创建一个新项目或通过npm安装Vue。 配置Vue JSX插件&#xff1a;在创建的项目中&#xff0c;找到 babel.config.js 文件&#xff0c;添加以下插件配置&#xff1a; module.exports {presets: [vue…

CentOS Linux MySQL 数据库 的安装方法

一、简单了解MySQL数据库的体系结构 &#xff08;一&#xff09;MySQL架构图 &#xff08;二&#xff09;MySQL体系结构&#xff1a;连接层、服务层、引擎层、存储层 1、连接层--主要职责&#xff1a;身份认证&#xff0c;连接管理&#xff0c;获取权限信息 &#xff08;1&am…

No11.精选前端面试题,享受每天的挑战和学习

文章目录 JS数组去重的几个方法讲下es6新增symbol 数据类型v-model原理是什么vue响应式原理vue中的data 为什么是个函数&#xff1f;前端有几种缓存方式 JS数组去重的几个方法 在JavaScript中&#xff0c;可以使用几种方法对数组进行去重&#xff1a; 使用Set&#xff1a;Set…

每日汇评:美联储会议纪要是否能确认黄金的看涨楔形?

1、在美国独立日清淡的交易中&#xff0c;黄金价格创下了一周以来的新高&#xff1b; 2、在美联储会议纪要之前&#xff0c;美元利用了对经济衰退的担忧和中美科技之争&#xff1b; 3、黄金需要日线收在1922美元上方才能确认看涨楔形&#xff0c;但看跌的RSI值得谨慎&#xf…

png转svg图片免费

svg免费转换网站 https://vectr.com/design/editor/c232c8cb-5eb8-4bae-b302-25cb94a8f737 操作步骤 1.上传png或者其他格式图片 2.点击导出文件 3.选择导出格式为svg和其他配置参数 4.打开下载好的svg图片 5.在编辑器中看svg图片