当前位置: 首页 > news >正文

Scala第十六章节

Scala第十六章节

scala总目录
文档资料下载

章节目标

  1. 掌握泛型方法, 类, 特质的用法
  2. 了解泛型上下界相关内容
  3. 了解协变, 逆变, 非变的用法
  4. 掌握列表去重排序案例

1. 泛型

泛型的意思是泛指某种具体的数据类型, 在Scala中, 泛型用[数据类型]表示. 在实际开发中, 泛型一般是结合数组或者集合来使用的, 除此之外, 泛型的常见用法还有以下三种:

  • 泛型方法
  • 泛型类
  • 泛型特质
1.1 泛型方法

泛型方法指的是把泛型定义到方法声明上, 即:该方法的参数类型是由泛型来决定的. 在调用方法时, 明确具体的数据类型.

格式

def 方法名[泛型名称](..) = {//...
}

需求

定义方法getMiddleElement(), 用来获取任意类型数组的中间元素.

  • 思路一: 不考虑泛型直接实现(基于Array[Int]实现)
  • 思路二: 加入泛型支持.

参考代码

//案例: 泛型方法演示.
//细节: 泛型方法在调用方法的时候 明确具体的数据类型.
object ClassDemo01 {//需求: 用一个方法来获取任意类型数组的中间的元素//思路一:不考虑泛型直接实现(基于Array[Int]实现)//def getMiddleElement(arr: Array[Int]) = arr(arr.length / 2)//思路二: 加入泛型支持def getMiddleElement[T](arr: Array[T]) = arr(arr.length / 2)def main(args: Array[String]): Unit = {//调用方法println(getMiddleElement(Array(1, 2, 3, 4, 5)))println(getMiddleElement(Array("a", "b", "c")))}
}
1.2 泛型类

泛型类指的是把泛型定义到类的声明上, 即:该类中的成员的参数类型是由泛型来决定的. 在创建对象时, 明确具体的数据类型.

格式

class[T](val 变量名: T)

需求

  1. 定义一个Pair泛型类, 该类包含两个字段,且两个字段的类型不固定.
  2. 创建不同类型的Pair泛型类对象,并打印.

参考代码

//案例: 泛型-演示泛型类的使用.
//泛型类: 在创建对象的时候, 明确具体的数据类型.
object ClassDemo02 {//1. 实现一个Pair泛型类//2. Pair类包含两个字段,而且两个字段的类型不固定class Pair[T](var a:T, var b:T)def main(args: Array[String]): Unit = {//3. 创建不同类型泛型类对象,并打印var p1 = new Pair[Int](10, 20)println(p1.a, p1.b)var p2 = new Pair[String]("abc", "bcd")println(p2.a, p2.b)}
}
1.3 泛型特质

泛型特质指的是把泛型定义到特质的声明上, 即:该特质中的成员的参数类型是由泛型来决定的. 在定义泛型特质的子类或者子单例对象时, 明确具体的数据类型.

格式

trait 特质A[T] {//特质中的成员
}class 类B extends 特质A[指定具体的数据类型] {//类中的成员
}

需求

  1. 定义泛型特质Logger, 该类有一个变量a和show()方法, 它们都是用Logger特质的泛型.
  2. 定义单例对象ConsoleLogger, 继承Logger特质.
  3. 打印单例对象ConsoleLogger中的成员.

参考代码

//案例: 演示泛型特质.
object ClassDemo03 {//1. 定义泛型特质Logger, 该类有一个a变量和show()方法, 都是用Logger特质的泛型.trait Logger[T] {//定义变量val a:T//定义方法.def show(b:T) = println(b)}//2. 定义单例对象ConsoleLogger, 继承Logger特质.object ConsoleLogger extends Logger[String]{override val a: String = "张三"}//main方法, 作为程序的主入口.def main(args: Array[String]): Unit = {//3. 打印单例对象ConsoleLogger中的成员.println(ConsoleLogger.a)ConsoleLogger.show("10")}
}

2. 上下界

我们在使用泛型(方法, 类, 特质)时,如果要限定该泛型必须从哪个类继承、或者必须是哪个类的父类。此时,就需要使用到泛型的上下界

2.1 上界

使用T <: 类型名表示给类型添加一个上界,表示泛型参数必须要从该类(或本身)继承.

格式

[T <: 类型]

例如: [T <: Person]的意思是, 泛型T的数据类型必须是Person类型或者Person的子类型

需求

  1. 定义一个Person类
  2. 定义一个Student类,继承Person类
  3. 定义一个泛型方法demo(),该方法接收一个Array参数.
  4. 限定demo方法的Array元素类型只能是Person或者Person的子类
  5. 测试调用demo()方法,传入不同元素类型的Array

参考代码

//案例: 演示泛型的上下界之  上界.
object ClassDemo04 {//1. 定义一个Person类class Person//2. 定义一个Student类,继承Person类class Student extends Person//3. 定义一个demo泛型方法,该方法接收一个Array参数,//限定demo方法的Array元素类型只能是Person或者Person的子类def demo[T <: Person](arr: Array[T]) = println(arr)def main(args: Array[String]): Unit = {//4. 测试调用demo,传入不同元素类型的Array//demo(Array(1, 2, 3))          //这个会报错, 因为只能传入Person或者它的子类型.demo(Array(new Person()))demo(Array(new Student()))}
}
2.2 下界

使用T >: 数据类型表示给类型添加一个下界,表示泛型参数必须是从该类型本身或该类型的父类型.

格式

[T >: 类型]

注意:

  1. 例如: [T >: Person]的意思是, 泛型T的数据类型必须是Person类型或者Person的父类型
  2. 如果泛型既有上界、又有下界。下界写在前面,上界写在后面. 即: [T >: 类型1 <: 类型2]

需求

  1. 定义一个Person类
  2. 定义一个Policeman类,继承Person类
  3. 定义一个Superman类,继承Policeman类
  4. 定义一个demo泛型方法,该方法接收一个Array参数,
  5. 限定demo方法的Array元素类型只能是Person、Policeman
  6. 测试调用demo,传入不同元素类型的Array

参考代码

//案例: 演示泛型的上下界之 下界.
//如果你在设定泛型的时候, 涉及到既有上界, 又有下界, 一定是: 下界在前, 上界在后.
object ClassDemo05 {//1. 定义一个Person类class Person//2. 定义一个Policeman类,继承Person类class Policeman extends Person//3. 定义一个Superman类,继承Policeman类class Superman extends Policeman//4. 定义一个demo泛型方法,该方法接收一个Array参数,//限定demo方法的Array元素类型只能是Person、Policeman//          下界          上界def demo[T >: Policeman <: Policeman](arr: Array[T]) = println(arr)def main(args: Array[String]): Unit = {//5. 测试调用demo,传入不同元素类型的Array//demo(Array(new Person))demo(Array(new Policeman))//demo(Array(new Superman))     //会报错, 因为只能传入: Policeman类获取它的父类型, 而Superman是Policeman的子类型, 所以不行.}
}

3. 协变、逆变、非变

在Spark的源代码中大量使用到了协变、逆变、非变,学习该知识点对我们将来阅读spark源代码很有帮助。

  • 非变: 类A和类B之间是父子类关系, 但是Pair[A]和Pair[B]之间没有任何关系.
  • 协变: 类A和类B之间是父子类关系, Pair[A]和Pair[B]之间也有父子类关系.
  • 逆变: 类A和类B之间是父子类关系, 但是Pair[A]和Pair[B]之间是子父类关系.

如下图:
在这里插入图片描述

3.1 非变

语法格式

class Pair[T]{}
  • 默认泛型类是非变的
  • 即: 类型B是A的子类型,Pair[A]和Pair[B]没有任何从属关系
3.2 协变

语法格式

class Pair[+T]
  • 类型B是A的子类型,Pair[B]可以认为是Pair[A]的子类型
  • 参数化类型的方向和类型的方向是一致的。
3.3 逆变

语法格式

class Pair[-T]
  • 类型B是A的子类型,Pair[A]反过来可以认为是Pair[B]的子类型
  • 参数化类型的方向和类型的方向是相反的
3.4 示例

需求

  1. 定义一个Super类、以及一个Sub类继承自Super类
  2. 使用协变、逆变、非变分别定义三个泛型类
  3. 分别创建泛型类对象来演示协变、逆变、非变

参考代码

//案例: 演示非变, 协变, 逆变.
object ClassDemo06 {//1. 定义一个Super类、以及一个Sub类继承自Super类class Super               //父类class Sub extends Super   //子类//2. 使用协变、逆变、非变分别定义三个泛型类class Temp1[T]            //非变class Temp2[+T]           //协变class Temp3[-T]           //逆变.def main(args: Array[String]): Unit = {//3. 分别创建泛型类来演示协变、逆变、非变//演示非变.val t1:Temp1[Sub] = new Temp1[Sub]//val t2:Temp1[Super] = t1          //编译报错, 因为非变是: Super和Sub有父子类关系, 但是Temp1[Super] 和 Temp1[Sub]之间没有关系.//演示协变val t3:Temp2[Sub] = new Temp2[Sub]val t4:Temp2[Super] = t3          //不报错, 因为协变是: Super和Sub有父子类关系, 所以Temp2[Super] 和 Temp2[Sub]之间也有父子关系.//Temp2[Super]是父类型,   Temp2[Sub]是子类型.//演示逆变val t5:Temp3[Super]  = new Temp3[Super]val t6:Temp3[Sub] = t5          //不报错, 因为逆变是:  Super和Sub有父子类关系, 所以Temp3[Super] 和 Temp3[Sub]之间也有子父关系.//Temp3[Super]是子类型,   Temp3[Sub]是父类型.}
}

4. 案例: 列表去重排序

4.1 需求
  1. 已知当前项目下的data文件夹中有一个1.txt文本文件, 文件内容如下:

    11
    6
    5
    3
    22
    9
    3
    11
    5
    1
    2
    
  2. 对上述数据去重排序后, 重新写入到data文件夹下的2.txt文本文件中, 即内容如下:

    1
    2
    3
    5
    6
    9
    11
    22
    
4.2 目的

考察泛型, 列表, 流相关的内容.

4.3 参考代码
import java.io.{BufferedWriter, FileWriter}
import scala.io.Source//案例: 列表去重排序, 并写入文件.
object ClassDemo07 {def main(args: Array[String]): Unit = {//1. 定义数据源对象.val source = Source.fromFile("./data/1.txt")//2. 从指定文件中读取所有的数据(字符串形式)val list1:List[String] = source.mkString.split("\\s+").toList//3. 把List[String]列表转换成List[Int]val list2:List[Int] = list1.map(_.toInt)//4. 把List[Int]转换成Set[Int], 对列表元素去重.val set:Set[Int] = list2.toSet//5. 把Set[Int]转成List[Int], 然后升序排列val list3:List[Int] = set.toList.sorted//println(list3)//6. 把数据重新写入到data文件夹下的2.txt文件中.val bw = new BufferedWriter(new FileWriter("./data/2.txt"))for(i <- list3) {bw.write(i.toString)bw.newLine()    //别忘记加换行}//7. 释放资源bw.close()}
}

st[Int]转换成Set[Int], 对列表元素去重.
val set:Set[Int] = list2.toSet
//5. 把Set[Int]转成List[Int], 然后升序排列
val list3:List[Int] = set.toList.sorted
//println(list3)
//6. 把数据重新写入到data文件夹下的2.txt文件中.
val bw = new BufferedWriter(new FileWriter(“./data/2.txt”))
for(i <- list3) {
bw.write(i.toString)
bw.newLine() //别忘记加换行
}
//7. 释放资源
bw.close()
}
}

相关文章:

Scala第十六章节

Scala第十六章节 scala总目录 文档资料下载 章节目标 掌握泛型方法, 类, 特质的用法了解泛型上下界相关内容了解协变, 逆变, 非变的用法掌握列表去重排序案例 1. 泛型 泛型的意思是泛指某种具体的数据类型, 在Scala中, 泛型用[数据类型]表示. 在实际开发中, 泛型一般是结合…...

C语言 实现 链 显示 效果 查找 修改 删除

显示所有信息 2023年10月1日的描述:今天放假 2023年10月2日的描述:今天有体育 2023年10月3日的描述:今天有数学 2023年10月4日的描述:今天有语文 2023年10月5日的描述:今天有政治 2023年10月6日的描述:今天交学费 2023年10月7日的描述:今天周末 2023年10月8日的描述:今天给家里…...

CSS基础语法第一天

目录 一、CSS 简介 1.1 CSS简介 1.2 CSS语法 ​1.3 CSS 语法规范 1.4 CSS 代码风格 1.4.1 样式格式书写 1.4.2 样式大小写 ​1.4.3 空格规范 二、CSS 基础选择器 2.1选择器分类 2.2标签选择器 2.3 类选择器 2.4 id选择器 2.5 通配符选择器 三、盒子尺寸和背景色 …...

Leetcode 1492.n的第k个因子

给你两个正整数 n 和 k 。 如果正整数 i 满足 n % i 0 &#xff0c;那么我们就说正整数 i 是整数 n 的因子。 考虑整数 n 的所有因子&#xff0c;将它们 升序排列 。请你返回第 k 个因子。如果 n 的因子数少于 k &#xff0c;请你返回 -1 。 示例 1&#xff1a; 输入&#…...

十一工具箱流量主小程序源码

无授权&#xff0c;去过滤机制版本 看到网上发布的都是要授权的 朋友叫我把他去授权&#xff0c;能用就行 就把过滤去了 这样就不用授权 可以免费使用 白嫖党专属 一切接口可用&#xff0c;无需担心不能用 授权者不关站一直可以用 源码下载&#xff1a;https://download.csdn.…...

10.5汇编语言整理

【汇编语言相关语法】 1.汇编语言的组成部分 1.伪操作&#xff1a;不参与程序的执行&#xff0c;但是用于告诉编译器程序该怎么编译 .text .global .end .if .else .endif .data 2.汇编指令 编译器将一条汇编指令编译成一条机器码&#xff0c;在内存里一条指令占4字节内存&…...

Connect to 127.0.0.1:1080 [/127.0.0.1] failed: Connection refused: connect

报错信息 A problem occurred configuring root project CourseSelection. > Could not resolve all artifacts for configuration :classpath.> Could not resolve com.android.tools.build:gradle:3.6.1.Required by:project :> Could not resolve com.android.tool…...

驱动器类产品的接口EMC拓扑方案

驱动器类产品的接口EMC拓扑方案 1. 概述 本文以高压伺服驱动器和变频器类产品为例&#xff0c;对常用端口滤波拓扑方案进行总结&#xff0c;后续根据不同的应用场景可进行适当删减&#xff0c;希望对大家有帮助。 2. 驱动器验证等级 本文推荐拓扑的实验结果&#xff0c;满足…...

2023最新ICP备案查询系统源码 附教程 Thinkphp框架

2023最新ICP备案查询系统源码 附教程 thinkphp框架 本系统支持网址备案&#xff0c;小程序备案&#xff0c;APP备案查询&#xff0c;快应用备案查询 优势&#xff1a; 响应速度快&#xff0c;没有延迟&#xff0c;没有缓存&#xff0c;数据与官方同步 源码下载&#xff1a;ht…...

大数据Doris(六):编译 Doris遇到的问题

文章目录 编译 Doris遇到的问题 一、js_generator.cc:(.text+0xfc3c): undefined reference to `well_known_types_js’...

vue重修004上部

文章目录 版权声明组件的三大组成部分scoped解决样式冲突scoped原理2.代码演示 组件data函数说明演示 组件通信组件关系分类通信解决方案父子通信流程子向父通信代 props详解props校验props&data、单向数据流 小黑记事本&#xff08;组件版&#xff09;基础组件结构需求和实…...

【C++ techniques】要求/禁止/判断—对象产生于堆中

有时候我们想让某种对象具有“自杀”的能力&#xff0c;所以我们必须要求对象存在堆中&#xff0c;以便我们调用delete this&#xff1b;另一些时候&#xff0c;我们要求拥有某种确定性&#xff0c;保证某一些类型绝不会发生内存泄漏&#xff0c;原因是没有任何一个该类型的对象…...

吃鸡高手亲授:玩转绝地求生,分享顶级游戏干货!

绝地求生&#xff08;PUBG&#xff09;自上线以来&#xff0c;成为了全球热门游戏。作为吃鸡行家&#xff0c;我将分享一些独家技巧和干货&#xff0c;帮助您提高游戏战斗力&#xff0c;享受顶级游戏作战体验&#xff01; 首先&#xff0c;让我们谈一谈战斗力升级。想要在吃鸡游…...

Vue中如何进行自定义图表与可视化图形设计

Vue中如何进行自定义图表与可视化图形设计 在现代Web应用程序开发中&#xff0c;数据可视化图表和图形设计是至关重要的一部分。Vue.js是一个流行的JavaScript框架&#xff0c;它提供了强大的工具来构建交互性强大的用户界面。本文将探讨如何在Vue.js中进行自定义图表和可视化…...

学信息系统项目管理师第4版系列19_质量管理

1. 公差 1.1. 质量测量中公差是测量指标的可允许变动范围&#xff0c;而不是实际测量值与预期值的差 1.1.1. 【高22下选35】 1.2. 结果的的可接受范围 2. 控制界限 2.1. 统计意义上稳定的过程或过程绩效的普通偏差的边界 3. 3版 3.1. 质量控制新七工具 3.1.1. 【高19下…...

react库的基础学习

React介绍 React.js是前端三大新框架&#xff1a;Angular.js、React.js、Vue.js之一&#xff0c;这三大新框架的很多理念是相同的&#xff0c;但是也有各自的特点。 React起源于Facebook的内部项目&#xff0c;因为该公司对市场上所有 JavaScript MVC 框架&#xff0c;都不满…...

FFmpeg 基础模块:容器相关的 API 操作

目录 AVFormat 模块 AVFormat 前处理部分 AVFormat 读写处理部分 小结 思考 FFmpeg 目录中包含了 FFmpeg 库代码目录、构建工程目录、自测子系统目录等&#xff0c;具体内容如下&#xff1a; 现在你知道 FFmpeg 的源代码目录中都包含了哪些内容&#xff0c;在之后使用 FFm…...

SpringMVC+统一表现层返回值+异常处理器

一、统一表现层返回值 根据我们不同的处理方法&#xff0c;返回的数据格式都会不同&#xff0c;例如添加只返回true|false&#xff0c;删除同理&#xff0c;而查询却返回数据。 Result类 为此我们封装一个result类来用于表现层的返回。 public class Result {//描述统一格式…...

2023年地理信息系统与遥感专业就业前景与升学高校排名选择

活动地址&#xff1a;毕业季进击的技术er 地理信息系统&#xff08;GIS&#xff0c;Geographic Information System&#xff09;&#xff0c;又称“地理信息科学”&#xff08;Geographic Information Science&#xff09;&#xff0c;是一种具有信息系统空间专业形式的数据管理…...

第五章:最新版零基础学习 PYTHON 教程—Python 字符串操作指南(第二节 - Python 字符串—Python 字符串 len()的语法)

Python len() 函数返回字符串的长度。 目录 Python len() 语法 Python len() 示例 示例 1:带有元组和字符串的 Len() 函数...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...