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 = 180val EQ = 180override 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:Stringprintln("父类",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:Stringprintln("父类",filename)//lazy表示,不立刻求值,而是等到这个变量被使用的时候,去求值//lazy val fileout = new PrintWriter(filename)  去掉lazyval 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 FileLoggert1.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.多重继承的惰性求值

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

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

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

相关文章

Python+Appium+Pytest+Allure自动化测试框架-代码篇

文章目录 自动化测试框架工程目录示例测试代码示例结果查看allurepytest编写pytest测试样例的规则pytest conftest.py向测试函数传参 appium启动appium服务代码端通过端口与appium服务通信对设备进行操作在pytest测试用例中调用appium 更多功能 PythonAppiumPytestAllure自动化…

【C++】红黑树的Iterator改造以及mapset的模拟实现与封装

目录 01.红黑树的迭代器 operator: operator*、-> operator、! 02.红黑树的改造 begin和end方法 keyOfValue insert方法 find方法 size方法 clear方法 03.map&set的模拟实现 01.红黑树的迭代器 前面的博客我们介绍了红黑树的底层原理并手撕了一个自己的红…

微信小程序服务通知

项目中用到了小程序的服务消息通知,通知订单状态信息,下边就是整理的一下代码,放到项目中,把项目的小程序appid和小程序的secret写进去,直接运行即可 提前申请好小程序服务信息通知短信模板,代码需要用到模…

linux命令行的艺术

文章目录 前言基础日常使用文件及数据处理系统调试单行脚本冷门但有用仅限 OS X 系统仅限 Windows 系统在 Windows 下获取 Unix 工具实用 Windows 命令行工具Cygwin 技巧 更多资源免责声明 熟练使用命令行是一种常常被忽视,或被认为难以掌握的技能,但实际…

2024年最新版SSL证书

SSL证书行业变动很大,随着操作系统,浏览器新版本不断增加,对SSL证书兼容性要求越来也高,对于安全性也有所提升,主流CA机构根证书及交叉链迎来了换新,这是为了延续下一个20个年的安全计划的提前不如&#xf…

Spark入门到实践

Spark入门到实践 一、Spark 快速入门1.1 Spark 概述1.2 Spark 最简安装1.3 Spark实现WordCount1.3.1 下载安装Scala1.3.2 添加Spark依赖1.3.3 Scala实现WordCount1.3.4 通过IDEA运行WordCount1.3.5 IDEA配置WordCount输入与输出路径1.3.6 通过IDEA运行WordCount1.3.7 查看运行结…

vue、小程序腾讯地图开放平台使用

一、登录账号 腾讯地图API 官方文档: 腾讯位置服务 - 立足生态,连接未来 二、申请秘钥 key 从首页【开发文档】-【微信小程序 SDK】进到微信小程序的开发文档:微信小程序JavaScript SDK | 腾讯位置服务 然后我们根据【Hello World】的提示…

电赛入门之软件stm32keil+cubemx

hal库可以帮我们一键生成许多基本配置,就不需要自己写了,用多了hal库就会发现原来用基本库的时候都过的什么苦日子(笑 下面我们以f103c8t6,也就是经典的最小核心板来演示 一、配置工程 首先来新建一个工程 这里我们配置rcc和sys&…

Elasticsearch开源仓库404 7万多star一夜清零

就在昨晚,有开发者惊奇地发现自己的开源项目 star 数竟然超过了最流行的开源全文搜索引擎 Elasticsearch。发生了什么事?Elasticsearch 竟然跌得比股票还凶 —— 超 7 万 star 的 GitHub 仓库竟然只剩下 200 多。 从社交媒体的动态来看,Elast…

汽车免拆诊断案例 | 2010款起亚赛拉图车发动机转速表指针不动

故障现象  一辆2010款起亚赛拉图车,搭载G4ED 发动机,累计行驶里程约为17.2万km。车主反映,车辆行驶正常,但组合仪表上的发动机转速表指针始终不动。 故障诊断  接车后进行路试,车速表、燃油存量表及发动机冷却温度…

【电商搜索】现代工业级电商搜索技术-亚马逊-经典的Item-to-Item协同推荐算法

【电商搜索】现代工业级电商搜索技术-亚马逊-经典的Item-to-Item协同推荐算法 文章目录 【电商搜索】现代工业级电商搜索技术-亚马逊-经典的Item-to-Item协同推荐算法1. 论文信息2. 算法介绍3. 创新点小结4. 实验效果5. 算法结论6. 代码实现7. 问题及优化方向1. 冷启动问题2. 稀…

Java - 数组实现大顶堆

题目描述 实现思路 要实现一个堆,我们首先要了解堆的概念。 堆是一种完全二叉树,分为大顶堆和小顶堆。 大顶堆:每个节点的值都大于或等于其子节点的值。 小顶堆:每个节点的值都小于或等于其子节点的值。 完全二叉树&#xff…

人工智能与数据安全:Facebook如何应对隐私挑战

在数字时代,数据隐私和安全成为了用户和企业关注的核心问题。作为全球最大的社交媒体平台之一,Facebook面临着日益严峻的隐私挑战。近年来,频繁发生的数据泄露事件和对用户隐私的质疑,使得Facebook在保护用户数据方面倍感压力。为…

2024年ABS分区更新,聚焦管理科学领域新动态

2024学术期刊指南简介 2024年10月30日,英国商学院协会(Chartered Association of Business Schools)发布了最新的《学术期刊指南(Academic Journal Guide)》(以下简称“《指南》”)&#xff0c…

解读!中国人工智能大模型技术白皮书!

近期,中国人工智能协会发布了《中国人工智能大模型技术白皮书》,系统梳理了大模型技术演进,深入探讨关键技术要素,并剖析当前挑战及未来展望。我为大家做了简要总结,并附上原文供深入阅读。 目录 第 1 章 大模型技术概…

深度学习笔记之BERT(一)BERT的基本认识

深度学习笔记之BERT——BERT的基本认识 引言回顾:Transformer的策略回顾:Word2vec的策略和局限性 BERT \text{BERT} BERT的基本理念抽象的双向BERT的预训练策略 预训练与微调 引言 从本节开始,将介绍 BERT \text{BERT} BERT系列模型以及其常…

二:Linux学习笔记(第一阶段)-- Linux命令

目录 Linux注意事项: Linux目录 Linux系统基础命令 1. 文件和目录操作 2. 文件查看和编辑 3. 文件权限和所有权 4. 系统信息 5. 网络命令 6. 文件查找 7. 压缩和解压缩 8. 系统管理 Linux注意事项: 严格区分大小写一切皆文件windows下的程序不…

基于 Java 语言双代号网络图自动绘制系统

基于Java语言双代号网络图自动绘制系统研究与实现 一、摘要 网络计划技术已被广泛应用于工业、农业、国防、科学研究等多个领域中的项目计划与管理,以缩短项目周期,提高资源的利用效率。在网络计划技术中,绘制网络图是网络计划技术的基础工…

多模态大模型微调实践!PAI+LLaMA Factory搭建AI导游

一、引言 AI的快速发展推动了各行各业的智能化转型和创新,随之而来的是对AI应用的迫切需求。 如何微调大模型、高效搭建AI应用成为了开发者们广泛关注的技术方向。阿里云人工智能平台PAI,联合开源低代码大模型微调框架LLaMA Factory ,共同打…

设计模式-单例模型(单件模式、Singleton)

单例模式是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。 单例模式同时解决了两个问题, 所以违反了单一职责原则: 保证一个类只有一个实例。 为什么会有人想要控制一个类所拥有的实例…