目录

泛型

定义一个泛型方法

定义一个泛型类

上下界

协变、逆变、非变

非变

协变

逆变


泛型

scala和Java一样,类和特质、方法都可以支持泛型。我们在学习集合的时候,一般都会涉及到泛型。

scala> val list1:List[String] = List("1", "2", "3")
list1: List[String] = List(1, 2, 3)scala> val list1:List[String] = List("1", "2", "3")
list1: List[String] = List(1, 2, 3)

在scala中,使用方括号来定义类型参数。

定义一个泛型方法

需求:用一个方法来获取任意类型数组的中间的元素

不考虑泛型直接实现(基于Array[Int]实现)

加入泛型支持

不考虑泛型的实现

def getMiddle(arr:Array[Int]) = arr(arr.length / 2)def main(args: Array[String]): Unit = {val arr1 = Array(1,2,3,4,5)println(getMiddle(arr1))}

加入泛型支持

  def getMiddle[A](arr:Array[A]) = arr(arr.length / 2)def main(args: Array[String]): Unit = {val arr1 = Array(1,2,3,4,5)val arr2 = Array("a", "b", "c", "d", "f")println(getMiddle[Int](arr1))println(getMiddle[String](arr2))// 简写方式println(getMiddle(arr1))println(getMiddle(arr2))}

定义一个泛型类

我们接下来要实现一个Pair类(一对数据)来讲解scala泛型相关的知识点。

Pair类包含两个值,而且两个值的类型不固定。

// 类名后面的方括号,就表示这个类可以使用两个类型、分别是T和S
// 这个名字可以任意取

class Pair[T, S](val first: T, val second: S) case class Person(var name:String, val age:Int)object Pair {def main(args: Array[String]): Unit = {val p1 = new Pair[String, Int]("张三", 10)val p2 = new Pair[String, String]("张三", "1988-02-19")val p3 = new Pair[Person, Person](Person("张三", 20), Person("李四", 30))}
}

要定义一个泛型类,直接在类名后面加上方括号,指定要使用的类型参数。上述的T、S都是类型参数,就代表一个类型

指定了类对应的类型参数后,就可以使用这些类型参数来定义变量了

上下界

现在,有一个需求,在Pair类中,我们只想用来保存Person类型的对象,因为我们要添加一个方法,让好友之间能够聊天。例如:

def chat(msg:String) = println(s"${first.name}对${second.name}说: $msg")

但因为,Pair类中根本不知道first有name这个字段,上述代码会报编译错误。

而且,添加了这个方法,就表示Pair类,现在只能支持Person类或者Person的子类的泛型。所以,我们需要给Pair的泛型参数,添加一个上界。

使用<: 类型名表示给类型添加一个上界,表示泛型参数必须要从上界继承。

// 类名后面的方括号,就表示这个类可以使用两个类型、分别是T和S
// 这个名字可以任意取
class Pair[T <: Person, S <:Person](val first: T, val second: S) {def chat(msg:String) = println(s"${first.name}对${second.name}说: $msg")
}class Person(var name:String, val age:Int)object Pair {def main(args: Array[String]): Unit = {val p3 = new Pair(new Person("张三", 20), new Person("李四", 30))p3.chat("你好啊!")}
}

接着再提一个需求,Person类有几个子类,分别是Policeman、Superman。

要控制Person只能和Person、Policeman聊天,但是不能和Superman聊天。此时,还需要给泛型添加一个下界。

// 类名后面的方括号,就表示这个类可以使用两个类型、分别是T和S
// 这个名字可以任意取
class Pair[T <: Person, S >: Policeman <:Person](val first: T, val second: S) {def chat(msg:String) = println(s"${first.name}对${second.name}说: $msg")
}class Person(var name:String, val age:Int)
class Policeman(name:String, age:Int) extends Person(name, age)
class Superman(name:String) extends Policeman(name, -1)object Pair {def main(args: Array[String]): Unit = {
// 编译错误:第二个参数必须是Person的子类(包括本身)、Policeman的父类(包括本身)val p3 = new Pair(new Person("张三", 20), new Superman("李四"))p3.chat("你好啊!")}
}

U >: T 表示U必须是类型T的父类或本身

S <: T 表示S必须是类型T的子类或本身

协变、逆变、非变 

父类对象 可以指向 子类的实例,这是多态

如果是泛型之间呢?

来一个类型转换的问题:

class Pair[T]object Pair {def main(args: Array[String]): Unit = {val p1 = Pair("hello")// 编译报错,无法将p1转换为p2val p2:Pair[AnyRef] = p1println(p2)}
}

非变

class Pair[T]{},这种情况就是非变(默认),类型B是A的子类型,Pair[A]和Pair[B]没有任何从属关系,这种情况和Java是一样的。

协变

class Pair[+T],这种情况是协变。类型B是A的子类型,Pair[B]可以认为是Pair[A]的子类型。这种情况,参数化类型的方向和类型的方向是一致的。

逆变

class Pair[-T],这种情况是逆变。类型B是A的子类型,Pair[A]反过来可以认为是Pair[B]的子类型。这种情况,参数化类型的方向和类型的方向是相反的。

示例:

class Super
class Sub extends Super//非变
class Temp1[A](title: String)
//协变
class Temp2[+A](title: String)
//逆变
class Temp3[-A](title: String)object Covariance_demo {def main(args: Array[String]): Unit = {val a = new Sub()// 没有问题,Sub是Super的子类val b:Super = a// 非变val t1:Temp1[Sub] = new Temp1[Sub]("测试")// 报错!默认不允许转换// val t2:Temp1[Super] = t1// 协变val t3:Temp2[Sub] = new Temp2[Sub]("测试")val t4:Temp2[Super] = t3// 非变val t5:Temp3[Super] = new Temp3[Super]("测试")val t6:Temp3[Sub] = t5}
}

2021年大数据常用语言Scala(三十六):scala高级用法 泛型相关推荐

  1. 2021年大数据常用语言Scala(三十一):scala面向对象 特质(trait)

    目录 特质(trait) 作为接口使用 定义具体的方法 定义具体方法和抽象方法 定义具体的字段和抽象的字段 实例对象混入trait trait调用链 trait的构造机制 trait继承class 特 ...

  2. 2021年大数据常用语言Scala(三):Scala解释器

    目录 scala解释器 启动scala解释器 执行scala代码 退出解释器 scala解释器 后续我们会使用scala解释器来学习scala基本语法,scala解释器像Linux命令一样,执行一条代 ...

  3. 2021年大数据常用语言Scala(四):基础语法学习 声明变量

    目录 声明变量 语法格式 在解释器中定义一个变量 val和var变量 使用类型推断来定义变量 惰性赋值 声明变量 我们将来每一天编写scala程序都会定义变量.那scala语言如何定义变量呢? 语法格 ...

  4. 2021年大数据常用语言Scala(一):Scala简介

    目录 一.Scala简介 为什么使用scala Scala对比Java 案例 一.Scala简介 scala是运行在JVM上的多范式编程语言,同时支持面向对象和面向函数编程 多范式:就是包含多种编程思 ...

  5. 2021年大数据常用语言Scala(十八):基础语法学习 Map对象

    目录 Map对象 不可变Map 可变Map Map基本操作 Map对象 Map可以称之为映射.它是由键值对组成的集合.在scala中,Map也分为不可变Map和可变Map. 不可变Map 定义 语法 ...

  6. 2021年大数据常用语言Scala(二):Scala开发环境安装

    目录 开发环境安装 安装JDK 安装scala SDK 步骤 具体操作 安装IDEA scala插件 步骤 开发环境安装 学习如何编写scala代码之前,需要先安装scala编译器以及开发工具 sca ...

  7. 2021年大数据常用语言Scala(十七):基础语法学习 Set

    目录 Set 不可变集 可变集 Set Set(集)是代表没有重复元素的集合.Set具备以下性质: 元素不重复 不保证插入顺序 和List正好相反, List: 元素可以重复 保证插入顺序 scala ...

  8. 2021年大数据常用语言Scala(三十八):scala高级用法 隐式转换和隐式参数

    目录 隐式转换和隐式参数 隐式转换 自动导入隐式转换方法 隐式转换的时机 隐式参数 隐式转换和隐式参数 隐式转换和隐式参数是scala非常有特色的功能,也是Java等其他编程语言没有的功能.我们可以很 ...

  9. 2021年大数据常用语言Scala(三十七):scala高级用法 高阶函数用法

    目录 高阶函数用法 作为值的函数 匿名函数 柯里化(多参数列表) 闭包 高阶函数用法 Scala 混合了面向对象和函数式的特性,在函数式编程语言中,函数是"头等公民",它和Int. ...

最新文章

  1. vs2013 类名颜色显示黑色,无法修改
  2. 047_输出一下byte的所有值
  3. jseclipse 是eclipse插件,让你编写js代码感觉更爽
  4. [BUUCTF-pwn]——rip
  5. 转 执行计划突变分析
  6. java8 stream遍历_Java8中用法优雅的 Stream,性能也优雅吗?
  7. mysqli扩展是mysql扩展的增强版_PHP学习笔记【22】--PHP数据库编程 mysql扩展库 和mysqli扩展库...
  8. python运行怎么下一步_简明Python3教程 18.下一步是什么
  9. 360解压电脑版安装包_鲁大师电脑版2020下载-鲁大师pc版安装包exe下载v6.1020.3005.1020 官方最新版...
  10. 【剑指offer】题目20 顺时针打印矩阵
  11. 安装php_sqlsrv扩展
  12. 2021-06-24相对定位
  13. 头目一天不来,就公然上班睡觉,主管怎么当得
  14. 关于Tricomi方程的类型分析与标准型求解
  15. Java后端开发技术选型
  16. 大学数学新生入门学习数学方法导引 by Ph.D.王小龙
  17. 安徽省毫州市谷歌卫星地图下载(百度网盘离线包下载)
  18. (转载)互联网鄙视食物链大全
  19. 如何快速搞定技术女神
  20. python空间点赞_用Python登录好友QQ空间点赞的示例代码

热门文章

  1. 2022-2028年中国科技馆行业研究及前瞻分析报告
  2. docker常用命令详解
  3. ssh(Struts+spring+Hibernate)三大框架整合-简述
  4. 2022-2028年中国刨花板市场投资分析及前景预测报告(全卷)
  5. pip install 豆瓣源、清华源、阿里源、中国科技大学源
  6. LeetCode简单题之检查字符串是否为数组前缀
  7. 不是都需要ARM吗?
  8. Django 缓存6.2
  9. git clean和git reset结合用法
  10. Android ListView 点击item改变item的背景颜色(ListView实现光标移动)