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.rhkb.cn/news/461534.html

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

相关文章

硬件在环仿真建模之电路拓扑建模与数学建模

我们需要先明确一个问题,什么是电路拓扑式建模(后面简称拓扑建模)和数学建模? 电力电子系统的拓扑建模,从大类上都可以归入为物理式建模(Physics-Based Modeling),物理式建模的最大特点就是用户…

根据提交的二维数据得到mysql建表和插入数据实用工具

根据提交的二维数据得到mysql建表和插入数据实用工具,这是重构版本(之前有过)。 会通过数据的长度&#xff0c;类型&#xff0c;是否数字&#xff0c;是否唯一等做判断&#xff0c;且每千条一个插入语句以优化性能。 <?php //整理与分享&#xff1a;yujianyue<1505859…

从0开始electron+vue2搭建环境

使用环境&#xff1a;node版本16.16.0 目录 搭建vue项目安装electron打包electron 搭建vue项目 已有vue2的环境直接进项安装electron步骤 没有的请先移动到这里查看 vue2脚手架搭建项目流程 我就不另外记录了 安装electron 直接运行 vue add electron-builder安装完成后&…

Qt——QWidget

一.控件概述 Widget 是 Qt 中的核心概念. 英文原义是 "小部件"&#xff0c;我们也把它翻译为 "控件" 。 控件是构成⼀个图形化界面的基本要素。 像上述示例中的, 按钮, 列表视图, 树形视图, 单行输入框, 多行输入框, 滚动条, 下拉框等, 都可以称为 "…

最经典盲超分辨率数据集

一、背景 底层视觉的发展是否能够让我们真正地看清这个世界呢&#xff1f; 在单图超分中&#xff0c;非盲超分已经发展得较为成熟了&#xff0c;而盲超分和真实超分仍然有很多问题尚未解决。在我看来&#xff0c;盲超分只是真实超分的一个过渡&#xff0c;由于真实世界中退化…

Spring Boot 配置文件详解与最佳实践

目录 前言1. 配置文件的作用2. Spring Boot 主要配置内容2.1 Actuator 配置2.2 缓存配置2.3 核心配置2.4 数据库与数据迁移配置2.5 开发工具配置2.6 Docker Compose 配置2.7 JSON 配置2.8 安全配置 3. 多个配置文件的处理方法3.1 使用 Profile 文件区分环境3.2 结合优先级加载配…

【Stable Diffusion】

1、SD 模型 安装完SD软件后&#xff0c;必须搭配基础模型才能使用。 不同的基础模型&#xff0c;其画风和擅长的领域会有侧重。 Checkpoint大模型 大模型是 SD 的核心&#xff0c;用来控制生成图片的整个画面风格走势。 出图前要选择好合适的大模型&#xff0c;比如有些擅长…

吉林大学2023级数据结构上机实验第(1~2周)参考答案(关注我,在系统关闭后持续更新)

A 括号匹配&#xff08;进阶版&#xff09; 分数 10 编写程序检查给定字符串中包含的括号是否正确匹配&#xff0c;本题中的括号有{ }、[ ]、( )、< >四种。另外再加上一个新的约束条件&#xff1a;当有多种括号嵌套时&#xff0c;嵌套的顺序应为{ → [ → ( → <&…

【综合算法学习】(第十三篇)

目录 解数独&#xff08;hard&#xff09; 题目解析 讲解算法原理 编写代码 单词搜索&#xff08;medium&#xff09; 题目解析 解析算法原理 编写代码 解数独&#xff08;hard&#xff09; 题目解析 1.题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09;…

【C++】string 类模拟实现:深入探索字符串操作原理

快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f6a9;在之前的文章中我们学会了对string类函数的使用&#xff0c;现在让我们对其进行模拟实现吧~&#x1f6a9; 目录 &#x1f4af;引言 &#x1f4…

[c++高阶]AVL树的深度剖析模拟实现

1.前言 如果你不知道什么是二叉搜索树&#xff0c;那么请你一定要阅读以下文章。 [c高阶]二叉搜索树深度剖析-CSDN博客 二叉搜索树如果在已经有序的情况下进行插入的话&#xff0c;那么他的时间复杂度是O(N)&#xff0c;然后有时候的时间复杂度又是O(logN)&#xff0c;因此在实…

我在命令行下剪辑视频

是的&#xff0c;你不需要格式工厂&#xff0c;你也不需要会声会影&#xff0c;更不需要爱剪辑这些莫名其妙的流氓软件&#xff0c;命令行下视频处理&#xff0c;包括剪辑&#xff0c;转码&#xff0c;提取&#xff0c;合成&#xff0c;缩放&#xff0c;字幕&#xff0c;特效等…

Tita:什么是 360 评估?

360 评估是一个专业的反馈机会&#xff0c;使一组同事和经理能够提供有关同事绩效的反馈。与仅由其经理评估员工工作绩效的典型员工绩效评估不同&#xff0c;360 评估会考虑来自同事和报告员工的反馈&#xff0c;甚至包括客户和与员工互动的其他人。 Tita&#xff1a;什么是 3…

jenkins ssh 免密报错Host key verification failed.

jenkins 发布项目&#xff0c;ssh连接远程服务器时报错&#xff1a;Host key verification failed. 解决&#xff1a; 原因是生成的sshkey不是用的jenkins用户&#xff0c;所以切换用户到&#xff1a;jenkins重新生成sshkey su jenkins ssh-keygen -t rsa ssh-copy-id -i ~/…

【Linux第七课--基础IO】内存级文件、重定向、缓冲区、文件系统、动态库静态库

目录 引入内存级文件重新使用C文件接口 -- 对比重定向写文件读文件文件流 认识文件操作的系统接口open参数 -- flagflag的内容宏的传参方式 open关闭文件写文件读文件结论 引入文件描述符fd、对文件的理解理解一切皆文件方法集文件fd的分配规则 重定向代码的重定向输入重定向输…

创意设计的起点:十大网页设计模板网站

对于网页设计领域的专业人士和爱好者而言&#xff0c;从零开始构建一个网页可能会耗费大量的时间和劳力。幸运的是&#xff0c;我们可以通过使用现成的网页模板来提升工作效率并节省宝贵的时间。一个好的模板不仅能提高设计效率&#xff0c;还能激发出卓越的创意灵感。因此&…

鸿蒙Harmony-矩形绘制组件Rect使用详解

目录 一&#xff0c;定义 二&#xff0c;绘制自定义图形 三&#xff0c;作为其他控件背景使用 一&#xff0c;定义 Rect是鸿蒙提供的矩形绘制组件&#xff0c;利用该组件可以绘制矩形背景&#xff0c;矩形图案等 官方提供的参数和属性&#xff1a; 参数&#xff1a; 参数名…

netty之bootstrap源码分析

写在前面 本文看下bootstrap类。 1&#xff1a;正文 1.1&#xff1a;干啥的&#xff1f; 在进行netty编程的时候都是先创建一个bootstrap&#xff0c;然后设置很多的东西&#xff0c;如下代码&#xff08;服务端启动代码&#xff09;&#xff1a; ServerBootstrap b new …

c# WinForm弹出窗体时不获取焦点方法

WinForm开发的软件有时候需要在屏幕右下角弹窗进行一些提示&#xff0c;通常使用new MyForm().Show()即可实现此需求。 但是当MyForm显示出来时&#xff0c;会抢走原本窗体上的光标&#xff0c;导致原本在软件上比如打字或者其他操作被中断&#xff0c;非常不人性化&#xff0…

方差和标准差哪些事儿

1.方差 在概率论与数理统计中&#xff0c;方差用来度量随机变量和其数学期望&#xff08;即均值&#xff09;之间的偏离程度。方差是各个数据与平均数之差的平方和的平均数,即: s(1/n)[(x1-x_)^2 (x2-x_)^2 …(xn-x_)^2] 其中&#xff0c;x_表示样本的平均数&#xff0c;n表示…