Scala 的trait

  在Scala中,trait是一种特殊概念。trait可以作为接口,同时也可以定义抽象方法。类使用extends继承trait,在Scala中,无论继承类还是继承trait都用extends关键字。在Scala中, 类继承trait后必须实现其中的抽象方法,实现时不需要使用override关键字,同时Scala支持多重继承trait,使用with关键字即可。

1.1Scala的特质

  本节通过对Scala的特质概念、作用以及语法的相关阐述来说明Scala中的特质应用。通过与Java 中的接口相互对比可以加深对特质的了解。

1.Scala的特质定义

  由于Scala没有Java中接口的概念,所以Scala的特质就相当于Java中的接口,但是Scala的特质比接口的功能强大。Scala的特质定义如下:

trait identified{
}

  其中trait为定义特质的关键字,identified表示一个合法的标识,可以自定义。登中可以定义一些成员、属性或方法等。 

2.Scala的特质作用

  Scala的特质可以封装成员和方法。Java中的接口不提供具体的实现,Scala的特质同样也是封装一些成员属性和方法。例如定义一个Scala特质,相关代码如下:

trait Person{
   val name="scala"
   def a():Unit
}

  Scala的特质相当于抽象类和接口的合体。在JDK1.7中,Java的接口只能定义一些没实现的方法体和一些赋值的变量,而Scala的trait相当于接口和抽象类的合体。 

3.Scala的特质语法

  在Java中实现多接口可以通过implements关键字定义,例如定义一个类P实现多个接口(A和B 为接口),即class P implements A, B。而在Scala中定义特质A和B时,实现特质的语法为:extends A with B,A和B的位置可以互换。例如 class Pextends A with B表示在一个类中实现多个特质。当类P中混入类S时,S的位置必须在extends之后,特质A或B不可以与类S互换位置,但是A和B的位置可以互换,例如class P extends S with A with B。

1.2 Scala的trait的用法

下面主要介绍Scala的trait的用法:

·只有抽象方法的trait。 

·只有抽象成员和方法的trait。

·具体成员的变量和方法。

·对象继承特质。

相关代码如下:

//定义trait
//1.不是类,不能实例化
//2.它的构造器不能带参数!即:不能添加()
trait Shentihao{
//  abstract class Shentihao{
  //具体属性
  var KM_1 = 5
  //抽象属性
  var sports:String

  //具体方法
  def say(): Unit = {}
  //抽象方法
  def run
}

class Student1 extends Shentihao{
  var sports = "跳绳"

  def run():Unit={
    println("1000m 在4.5分钟内跑完")
  }
}

object Test20 {
  def main(args: Array[String]): Unit = {
    val s1 = new Student1()
  }
}

  对象继承特质是Scala中比较特殊的一点,可以为单独的某一对象继承trait。相关代码如下:

//多继承

//美貌
trait Beauty {
  val leg:Double

}

//智慧
trait Wisdom {
  val EQ:Int
}


//一个类,实现了两特质。用 with 隔开
//多个特质可以交换顺序
class Girl extends Beauty with Wisdom {
  val leg = 180
  val EQ = 180

  override def toString: String = s"leg=${leg},eq=${EQ}"
}
object Test20_1 {
  def main(args: Array[String]): Unit = {
    val girl = new Girl()
    println(girl)
  }
}

1.3 trait的mix 

  下面介绍一个类继承了一个特质后,特质中的成员的处理方式。成员分为抽象成员和具体成员。成员包括方法和属性,没有方法体实现的方法称为抽象方法,没有赋值的属性称为抽象属性;方法体中有具体实现的方法称为具体方法,赋予了一个具体值的属性称为具体属性。 

  抽象成员包括抽象方法和抽象属性。如果一个类继承了特质,那么抽象方法一定要实现方法体。抽象属性可以通过val或var关键字修饰,如果子类要访问由val或var修饰的抽象成员,要求变量修饰必须要对应,不加 override关键字。 

  具体成员包括具体方法和具体属性。如果是一个具体的方法,那么需要使用关键字override重写方法。使用override重写方法时,方法的名称、参数列表以及返回值必须相同。 具体属性同样使用val或var关键字修饰,val的重写需加上 override关键字,即override val 属性名称。var的重写不需override关键字和var修饰,只需属性名称即可。

1.4 trait的加载顺序

  在Java中构造器的调用顺序为先调用父类构造器再调用子类构造器。Scala 中的调用顺序与Java中的十分相似。trait的加载顺序为先执行超类(父类)中的构造器,再调用子类的构造器。如果混入的trait有父类,会按照继承关系先调用父类。如果有多个父类,则按照从左到右的顺序调用,最后才会调用本类构造器。当有超类调用构造器时按照从左到右、从父类到子类的顺序调用即可。 

//继承多个特质时,加载的顺序

//多个特质加载顺序
//1,先父后子
//2.从左到右
trait  A051{
  println("1")
}

trait B051{
  println("2")
}

class AB extends A051 with B051{
  println("AB")
}

object Test20_2 {
  def main(args: Array[String]): Unit = {
    new AB()
  }
}

下面定义多个父类和子类演示构造器的执行顺序。相关代码如下:

trait A051{ println("A051") }

trait AA051 extends A051 {println("AA051")}

trait AB051 extends A051 {println("AA051")}

trait B051 {println("B051")}

trait BA051 extends B051{println("BA051")}

trait BB051 extends B051 {println("BB051")}

class AB extends AA051 with BA051 with AB051 with BB051{
  println("AB")
}

object Test21{
  def main(args: Array[String]): Unit = {
    new AB()
  }
}

//A051 AA051 B051 BA051 AA051 BB051 AB

1.5 解决空指针异常问题

  通过前面的介绍,了解了Scala构造器的调用顺序并解释了父类构造器打印为0的问题。 下面介绍调用构造器引起的第二个问题,即空指针异常问题。 

1.trait的抽象成员父类使用问题

  在新定义一个对象时,该对象会先调用父类的构造器。而在父类构造器中由于变量没有赋值,实际相当于null,再通过变量(实际为null)调用方法时就会报空指针异常的问题。 

2.解决方法

  解空指针异常的方式有两种,分别是提前定义和懒加载。提前定义就是在调用对象之前给变量赋值,即提前定义法。懒加载就是在调用的过程中通过lazy关键字解决问题。 

下面定义一个Logger演示构造器执行顺序,造成空指针问题。相关代码如下:

方法1:使用lazy关键字

import java.io.PrintWriter
//经典错误:空指针异常

trait FileLogger{
  //抽象属性,没有=
  val filename:String
  println("父类",filename)

  //lazy表示,不立刻求值,而是等到这个变量被使用的时候,去求值
  lazy val fileout = new PrintWriter(filename)

  //用来把 msg 写入到对应文件中
  def log(msg: String): Unit ={
    fileout.println(msg)
    fileout.flush()
  }
}

class Test211 extends FileLogger{

  val filename = "2024-10-28.txt"
  println("子类",filename)
}

object Test21_1 {
  def main(args: Array[String]): Unit = {
    val t1 = new Test211()
    t1.log("test!")
  }
}

方法2:提前定义 

import java.io.PrintWriter
//经典错误:空指针异常

trait FileLogger{
  //抽象属性,没有=
  val filename:String
  println("父类",filename)

  //lazy表示,不立刻求值,而是等到这个变量被使用的时候,去求值
  //lazy val fileout = new PrintWriter(filename)  去掉lazy
  val fileout = new PrintWriter(filename)

  //用来把 msg 写入到对应文件中
  def log(msg: String): Unit ={
    fileout.println(msg)
    fileout.flush()
  }
}

class Test211 extends FileLogger{

  val filename = "2024-10-28.txt"
  println("子类",filename)
}

object Test21_1 {
  def main(args: Array[String]): Unit = {
//    val t1 = new Test211()
    val t1 = new {val filename="2024-10-29.txt"} with FileLogger
    t1.log("test!")
  }
}

1.6 trait与类的相关特性

  通过之前的介绍我们对trait和类都有了一个初步的了解,下面通过trait和类的相同点以及不同点来说明trait的相关特性。 

1.trait与类的相同点

  类和trait都以定义成员变量和方法,成员变量和方法可以是抽象的也可以是具体的。如果类是抽象类,则可以定义抽象成员和抽象方法,如果类是普通类,则可以定义一些普通的变量和方法。trait相当于抽象类和接口,所以trait 既可以定义抽象成员也可以定义普通成员。在继承方面它们都可以使用extends关键字。 

2.trait与类的不同点

  定义类或抽象类时可以有构造参数,而trait构造器不能带参数。关于多继承问题,Java中的类不支持多继承,接口支持多实现:而在Scala中trait可以支持多继承,也可以在多继承的同时混入多个特质。

1.7trait多继承
  下面从trait多继承的实现方法和混入多trait的语法格式对多继承做一个简单介绍,通过多继承产生的问题进一步加深对trait名继承的了解。下面简单介绍多继承广生的问题以解决方案。 

1.trait多继承的定义
  可以通过混入多个trait实现多继承。例如,定义特质t1、t2,在类A中混入多个特质,即class A extends tl with t2表示在类A中混入 t1和t2两个特质。 

2.混入多trait的语法
混入多trait的语法如下:

extends A with B with C

  其中多个特质可以互换位置,即可以 extends C with A with B。多个特质互换位置不影响实现多继承。

3.多重继承

  多重继承容易产生菱形问题。菱形问题可以描述为B和C继承自A,D继承自B和C,如果A有一个方法被B和C重载,而D不对其重载,那么D应该实现谁的方法,B还是C?解决菱形问题的方法是采用最右优先深度遍历进行搜索。

4.多重继承的惰性求值

  惰性求值相当于懒加载问题,即当使用时再去求它的值。当使用子类调用父类的方法出现惰性求值的问题时,只有调用父类中真正的方法时才会对子类中的方法求值。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

六西格玛项目助力,手术机器人零部件国产化稳中求胜——张驰咨询

项目背景 XR-1000型腔镜手术机器人是某头部手术机器人企业推出的高端手术设备,专注于微创手术领域,具有高度的精确性和稳定性。而XR-1000型机器人使用的部分核心零部件长期依赖进口,特别是高精度电机、关节执行机构和视觉系统等,…

基于Python爬虫与文本挖掘的网络舆情监控系统【附源码】

基于Python爬虫与文本挖掘的网络舆情监控系统 效果如下: 系统登录界面 注册页面界面 管理员主界面 用户界面 网络舆情管理界面 看板详细页面 系统简介界面 用户主界面 网络舆情界面 研究背景 随着网络空间舆论的日益活跃,其对社会事件的影响愈发显著。…

光影重塑 艺术无界——中央美术学院国际学院与北京曦烽摄影学院联展启幕

10月28日,中央美术学院国际学院与北京曦烽摄影学院联合举办的《重塑》摄影展,在中央美术学院国际学院艺术空间启幕。展览旨在打破传统“时尚摄影”的话语界限,通过镜头展现时尚的更多维度,既关注视觉美感,更深入挖掘时…

【Linux 25】网络套接字 socket 概念

文章目录 🌈 一、IP 地址概念⭐ 1. IP 地址的作用⭐ 2. 源 IP 地址和目的 IP 地址 🌈 二、端口号概念⭐ 1. 源端口号和目的端口号⭐ 2. 端口号范围划分⭐ 3. 端口号 VS 进程 ID⭐ 4. 套接字 socket 的概念 🌈 三、传输层的典型代表协议⭐ 1. …

配置mysql 主主模式 GTID

文章目录 一、前提二、修改my.cnf主1 10.255.131.9主2 10.255.131.10 三、配置主主3.1 配置主 10.255.131.93.2 配置从 10.255.131.103.3 配置主 10.255.131.103.4 配置从 10.255.131.9 四、验证五、同步问题排查以及恢复5.1 查看同步状态5.2 查看同步是否数据一致性&#xff0…

自动化研磨领域的革新者:半自动与自动自磨机的技术突破

据QYResearch调研团队最新报告“全球半自动和自动自磨机市场报告2023-2029”显示,预计2029年全球半自动和自动自磨机市场规模将达到5.3亿美元,未来几年年复合增长率CAGR为3.5%。 图00001. 半自动和自动自磨机,全球市场总体规模 如上图表/数据…

最长方连续方波信号

更多关于刷题的内容欢迎订阅我的专栏华为刷题笔记 该专栏题目包含两部分: 100 分值部分题目 200 分值部分题目 所有题目都会陆续更新,订阅防丢失 题目描述 输入一串方波信号,求取最长的完全连续交替方波信号,并将其输出&#x…

ARB链挖矿DApp系统开发模式定制

在区块链生态中,挖矿作为一种获取加密资产的方式,越来越受到关注。ARB链凭借其高效的性能和灵活的智能合约系统,成为了开发挖矿DApp的理想平台。本文将探讨ARB链挖矿DApp的开发模式定制,包括架构设计、功能实现以及最佳实践。 ARB…

YoloV8改进策略:Block改进|RFE模块,提高小物体的识别精度|即插即用|代码+修改过程

摘要 论文介绍 本文介绍了一种基于YOLOv5的人脸检测方法,命名为YOLO-FaceV2。该方法旨在解决人脸检测中的尺度变化、简单与困难样本不平衡以及人脸遮挡等问题。通过引入一系列创新模块和损失函数,YOLO-FaceV2在WiderFace数据集上取得了优异的表现,特别是在小物体、遮挡和困…

使用 Elasticsearch 进行语义搜索

Elasticsearch 是一款功能强大的开源搜索引擎,可用于全文搜索、分析和数据可视化。传统上,Elasticsearch 以其执行基于关键字/词汇的搜索的能力而闻名,其中文档基于精确或部分关键字匹配进行匹配。然而,Elasticsearch 已经发展到支…

计算机网络:网络层 —— 虚拟专用网 VPN

文章目录 虚拟专用网 VPN 概述内联网 VPN外联网 VPN 虚拟专用网 VPN 概述 虚拟专用网(Virtual Private Network,VPN):利用公用的因特网作为本机构各专用网之间的通信载体,这样形成的网络又称为虚拟专用网。 出于安全…

C语言函数嵌套调用

函数嵌套调用就是在一个函数中调用另一个函数; 看一个例子; max2函数返回2个整数中大的一个;max4中调用max2,实现返回4个整数中最大的一个; int max2(int, int); int max4(int, int, int, int);......void CCjjyyV…

C++:继承及其相关问题

继承的定义 继承机制是⾯向对象程序设计实现代码复⽤的重要⼿段,它允许我们在保持原有类特性的基础上进⾏扩展,增加⽅法 (成员函数) 和属性 (成员变量),从而产⽣的类,这样的类称为派⽣类,也称为子类。而这样的类就成为…

Centos7.9 x86架构部署

一、部署环境 表 1‑1 环境服务版本号系统centos7.9_2009运行环境1JDK1.8_321前端WEBNginx1.14数据库postgresqlpostgresql13postgis3.1pgrouting3.1消息队列rabbitmq3.8.16运行环境2erlang23.3.3.1 二、部署JDK 2.1下载JDK安装包 官网下载JDK8 官网地址: https…

【uniapp3】分享一个自己写的h5日历组件

简言 分享一下自己基于uniapp写的日历组件。如果不太满足你的需求,可以自己改造。 日历 实现分析: 页面显示 - 分为顶部显示和日历显示,我这里做了多行和单行显示两种情况,主要是当时看着手机的日历做的,手机上的…

Nginx安装配置详解

Nginx Nginx官网 Tengine翻译的Nginx中文文档 轻量级的Web服务器,主要有反向代理、负载均衡的功能。 能够支撑5万的并发量,运行时内存和CPU占用低,配置简单,运行稳定。 写在前 uWSGI与Nginx的关系 1. 安装 Windows 官网 Stabl…

Java版企电子招标采购系统源业码Spring Cloud + Spring Boot +二次开发+ MybatisPlus + Redis

功能描述 1、门户管理:所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含:招标公告、非招标公告、系统通知、政策法规。 2、立项管理:企业用户可对需要采购的项目进行立项申请,并提交审批,查看所…

MS01SF1 精准测距UWB模组助力露天采矿中的人车定位安全和作业效率提升

在当今矿业行业,随着全球对资源需求的不断增加和开采难度的逐步提升,传统的作业方式面临着越来越多的挑战。露天矿山开采,因其大规模的作业环境和复杂的地形特点,面临着作业人员的安全风险、设备调度的高难度以及资源利用率低下等…

【Web.路由】——路由模板

路由模板负责根据规则生成URL,从而使得请求可以正常访问到资源。 总之就是——》》》 规范如何写一个url,并且命名以方便进行管理。 在Asp.net core中的Http管道机制,UseRouting()和 UseEndpoints()这两个中间件来实现整个路由系统。关于asp…

c加加11第二弹~

1lambda 1.1.lambda表达式书写格式 [capture-list] (parameters) mutable -> return-type { statement} 1.2lambda表达式各部分说明 [capture-list] : 捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[]来判断接下来的代码是否为lamb…