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

完整教程:Scala 泛型

一、泛型

        Scala 和 Java 一样,类、特质、方法都支持泛型。泛型就是定义类、方法时不用指定具体数据类型,在使用时才传入具体适用类型,这样的好处就是支持多类型的复用。泛型的常见用法有以下几种:

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

1.1 泛型方法

        泛型方法指把泛型定义到方法声明上,即该方法的参数类型由泛型来决定,在调用该方法时再传入明确的数据类型。

语法格式:

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

例如:

object Test {def getMiddleElement[T](array:Array[T]) = array(array.length / 2)def main(args: Array[String]): Unit ={println(getMiddleElement(Array(1, 2, 3, 4, 5))) //3println(getMiddleElement(Array(1, 2, 3, 4, 5,6))) //4println(getMiddleElement(Array("a", "b", "c", "d", "e"))) //c}
}

1.2 泛型类

语法格式:

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

例如:

  • 实现一个 Pari 泛型样例类;
  • Pari 类包含两个字段,而且两个字段的类型不固定;
  • 创建不同类型泛型类对象;
case class Pair[T](var a:T, var b:T)
def main(args: Array[String]): Unit = {val pairList = List(Pair("Hadoop", "Storm"),Pair("Hadoop", 2008),Pair(1.0, 2.0),Pair("Hadoop", Some(1.9)))println(pairList)
}
//List(Pair(Hadoop,Storm), Pair(Hadoop,2008), Pair(1.0,2.0), Pair(Hadoop,Some(1.9)))

1.3 泛型特质

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

语法格式:

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

例如:

  • 定义一个泛型特质 Logger,该特质有一个变量 a 和 show() 方法;
  • 定义单例对象,继承 Logger 特质;
  • 打印单例对象中的成员;
object Test {trait Logger[T] {val a:Tdef show(b:T)}object ConsoleLogger extends Logger[String]{override val a:String = "lee"override def show(b:String):Unit = println(b)}def main(args:Array[String]):Unit = {println(ConsoleLogger.a)COnsoleLogger.show("abc")}
}
//lee
//abc

二、泛型的上下界

        在定义方法 / 类的泛型时,限定必须从哪个类继承、或者必须是哪个类的父类。此时就需要使用到上下界。

2.1 上界

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

[T <: 类型]

例子:

  • 定义一个 Person 类;
  • 定义一个 Student 类,继承 Person 类;
  • 定义一个 demo 泛型方法,该方法接收一个 Array 参数;
  • 限定 demo 方法的 Array 元素类型只能是 Person 或者 Person 的子类;
  • 测试调用 demo,传入不同元素类型的 Array;
class Person
class Student extends Person
def demo[T <: Person](a:Array[T]) = println(a)
def main(args: Array[String]): Unit = {demo(Array(new Person))demo(Array(new Student))// 编译出错,必须是Person的子类// demo(Array("hadoop"))
}

2.2 下界

        上界是要求必须是某个类的子类,而下界则是必须是某个类的父类(或本身)。

[T >: 类型]

注意:如果类既有上界又有下界。下界写在前面,上界写在后面,如下:

def demo[T >: Policeman <: Person ](array:Array[T]) = println(array)

例如:

  • 定义一个 Person 类;
  • 定义一个Policeman类,继承Person类
  • 定义一个Superman类,继承Policeman类
  • 定义一个demo泛型方法,该方法接收一个Array参数,
  • 限定demo方法的Array元素类型只能是Person、Policeman
  • 测试调用demo,传入不同元素类型的Array
package com.robot.scalademo
class Person
class Policeman extends Person
class Superman extends Policeman
object Demo {def demo[T >: Policeman](array:Array[T]) = println(array)def main(args: Array[String]): Unit = {demo(Array(new Person))demo(Array(new Policeman))// 编译出错:Superman是Policeman的子类// demo(Array(new Superman))}
}
/**demo(Array(new Person))demo(Array(new Policeman))// 编译出错:Superman是Policeman的* */
---------------------------------------------------------------------
//泛型既有上界也有下界
package com.robot.scalademo
class Human
class Person  extends  Human
class Policeman extends Person
class Superman extends Policeman
object Demo {def demo[T >: Policeman <: Person ](array:Array[T]) = println(array)def main(args: Array[String]): Unit = {demo(Array(new Person))demo(Array(new Policeman))// 编译出错:Superman是Policeman的子类// demo(Array(new Superman))// 编译出错:Human是Person的父类//demo(Array(new Human))}
}
/**demo(Array(new Person))demo(Array(new Policeman))// 编译出错:Superman是Policeman的* */

三、非变、协变、逆变

  • 非变: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] 没有任何从属关系;
  • Java 中是一样的;

3.2 协变

语法格式:

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

3.3 逆变

语法格式:

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

3.4 代码示例

  • 定义一个 Super 类、以及一个 Sub 类继承自 Super 类;
  • 使用协变、逆变、非变分别定义三个泛型类;
  • 分别创建泛型类来演示协变、逆变、非变;
object Demo {def main(args: Array[String]): Unit = {//非变案例演示val A:Temp1[Sub] = new Temp1[Sub]//val B:Temp1[Super] = A      //非变, 编译报错,不能赋值。//尽管类型A是B的子类型,Pair[A]和Pair[B]没有任何从属关系,参数化类型之间没有关系,不管原类型之间的关系// 协变案例演示val C: Temp2[Sub] = new Temp2[Sub]val D: Temp2[Super] = C//类型C是D的子类型,Pair[C]可以认为是Pair[D]的子类型,参数化类型的方向和类型的方向是一致的。// 逆变案例演示val E: Temp3[Super] = new Temp3[Super]val F: Temp3[Sub] = E//类型F是E的子类型,Pair[E]反过来可以认为是Pair[F]的子类型。参数化类型的方向和类型的方向是相反的}
}

http://www.jsqmd.com/news/371429/

相关文章:

  • 2026年降AIGC率用什么工具好?花了200块实测出这份清单
  • 毕业论文神器:5个AI写作平台横向对比
  • 毕业论文AI写作工具如何选?5个高口碑平台推荐
  • 2026年AI率从96%降到0%可能吗?亲历者分享完整降AI流程
  • Docker 入门看这一篇就够了:从 0 到部署 Java 和 Node 项目实战
  • 学术救星:7个AI降重工具精准评测
  • AI写论文工具怎么挑?5个优质网站盘点
  • 论文必备:7款高效AI降重工具推荐
  • 高校科研成果转化的生态协同之道——科技与产业共赢的新篇章
  • AI辅助毕业论文写作?这5个网站最实用
  • 构建区域创新生态,推动科技成果转化——从传统困局到协同共赢
  • AI核心知识97——大语言模型之 DL(简洁且通俗易懂版)
  • 毕业论文必备!5款AI写作工具实测排名
  • 人工智能逐渐替代我们的工作,我们怎么做比较好?
  • AI核心知识98——大语言模型之 Generative AI(简洁且通俗易懂版)
  • tkinter可以做出多复杂的界面?
  • MongoDB 索引限制
  • 深入解析:23 种经典设计模式的名称、意图及适用场景概述
  • Matplotlib 柱形图
  • macOS下安装 Office 全家桶
  • JavaScript 条件语句
  • 细胞力学仿真软件:MCell_(10).模拟结果的可视化
  • 细胞力学仿真软件:MCell_(8).数据后处理与分析
  • 为什么我还是无法理解Transformer?Transformer到底是什么?
  • 细胞力学仿真软件:MCell_(6).分子扩散与反应模拟
  • 35岁程序员收藏!大模型风口已至,月薪30K+AI岗正在批量诞生,免费学习资料领取_大龄程序员转行指南
  • 小白程序员必看!收藏这份大模型学习指南,解锁AI前沿技术与应用_2026大模型前沿技术原理及未来应用场景展望报告
  • AI 编程大突破:DeepSeek V4 即将发布,普通人也能成为“代码大师”!
  • 细胞力学仿真软件:MCell_(11).MCell与其他软件的结合使用
  • Arcgispro 000210报错:转换失败:waters.ERROR 000210:无法创建输出...如何解决?