专栏首页深圳java培训深圳大数据培训:泛型--【千锋】
原创

深圳大数据培训:泛型--【千锋】

深圳大数据培训:泛型--【千锋】

带有一个或多个类型参数的类是泛型的。

泛型类的定义:

//带有类型参数A的类定义 class Stack[A] { private var elements: List[A] = Nil //泛型方法 def push(x: A) { elements = x :: elements } def peek: A = elements.head def pop(): A = { val currentTop = peek     elements = elements.tail     currentTop   } }

泛型类的使用,用具体的类型代替类型参数A。

val stack = new Stack[Int] stack.push(1) stack.push(2) println(stack.pop)  // prints 2 println(stack.pop)  // prints 1

8.1.协变

定义一个类型List[+A],如果A是协变的,意思是:对类型A和B,A是B的子类型,那么List[A]是List[B]的子类型。

abstract class Animal { def name: String } case class Cat(name: String) extends Animal case class Dog(name: String) extends Animal

Scala标准库有一个泛型类sealed abstract class List[+A],因为其中的类型参数是协变的,那么下面的程序调用时成功的。

object CovarianceTest extends App { //定义参数类型List[Animal] def printAnimalNames(animals: List[Animal]): Unit = {     animals.foreach { animal => println(animal.name)     }   } val cats: List[Cat] = List(Cat("Whiskers"), Cat("Tom")) val dogs: List[Dog] = List(Dog("Fido"), Dog("Rex")) //传入参数类型为List[Cat] printAnimalNames(cats) // Whiskers // Tom //传入参数类型为List[Dog] printAnimalNames(dogs) // Fido // Rex }

8.2.逆变

定义一个类型Writer[-A],如果A是逆变的,意思是:对类型A和B,A是B的子类型,那么Writer[B]是Writer[A]的子类型。

abstract class Animal { def name: String } case class Cat(name: String) extends Animal case class Dog(name: String) extends Animal

定义对应上述类进行操作的打印信息类

abstract class Printer[-A] { def print(value: A): Unit } class AnimalPrinter extends Printer[Animal] { def print(animal: Animal): Unit = println("The animal's name is: " + animal.name) } class CatPrinter extends Printer[Cat] { def print(cat: Cat): Unit = println("The cat's name is: " + cat.name) }

逆变的测试

object ContravarianceTest extends App { val myCat: Cat = Cat("Boots") //定义参数类型为Printer[Cat] def printMyCat(printer: Printer[Cat]): Unit = {     printer.print(myCat)   } val catPrinter: Printer[Cat] = new CatPrinter val animalPrinter: Printer[Animal] = new AnimalPrinter printMyCat(catPrinter) //可以传入参数类型为Printer[Animal] printMyCat(animalPrinter) }

8.3.上界

上界定义: T <: A ,表示类型变量T 必须是 类型A 子类

abstract class Animal { def name: String } abstract class Pet extends Animal {} class Cat extends Pet { override def name: String = "Cat" } class Dog extends Pet { override def name: String = "Dog" } class Lion extends Animal { override def name: String = "Lion" } //参数类型须是Pet类型的子类 class PetContainer[P <: Pet](p: P) { def pet: P = p } //Dog是Pet类型的子类 val dogContainer = new PetContainer[Dog](new Dog) //Cat是Pet类型的子类 val catContainer = new PetContainer[Cat](new Cat) //Lion不是Pet类型的子类,编译通不过 //  val lionContainer = new PetContainer[Lion](new Lion)

8.4.下界

语法 B >: A 表示参数类型或抽象类型 B 须是类型A的父类。通常,A是类的类型参数,B是方法的类型参数。

上面这段代码,因为作为协变类型的B,出现在需要逆变类型的函数参数中,导致编译不通过。解决这个问题,就需要用到下界的概念。

trait Node[+B] {   def prepend[U >: B](elem: U): Node[U] } case class ListNode[+B](h: B, t: Node[B]) extends Node[B] {   def prepend[U >: B](elem: U): ListNode[U] = ListNode(elem, this)   def head: B = h   def tail: Node[B] = t } case class Nil[+B]() extends Node[B] {   def prepend[U >: B](elem: U): ListNode[U] = ListNode(elem, this) }

测试

trait Bird case class AfricanSwallow() extends Bird case class EuropeanSwallow() extends Bird val africanSwallowList= ListNode[AfricanSwallow](AfricanSwallow(), Nil()) val birdList: Node[Bird] = africanSwallowList birdList.prepend(new EuropeanSwallow)

8.5 视界(view bounds)

注意:已过时,了解即可

视界定义: A <% B ,表示类型变量A 必须是 类型B`的子类,或者A能够隐式转换到B

class Pair_Int[T <% Comparable[T]] (val first: T, val second: T){ def bigger = if(first.compareTo(second) > 0) first else second } class Pair_Better[T <% Ordered[T]](val first: T, val second: T){ def smaller = if(first < second) first else second } object View_Bound { def main(args: Array[String]) { // 因为Pair[String] 是Comparable[T]的子类型, 所以String有compareTo方法 val pair = new Pair_Int("Spark", "Hadoop"); println(pair.bigger) /** * Scala语言里 Int类型没有实现Comparable; * 那么该如何解决这个问题那; * 在scala里 RichInt实现了Comparable, 如果我们把int转换为RichInt类型就可以这样实例化了. * 在scala里 <% 就起这个作用, 需要修改Pair里的 <: 为<% 把T类型隐身转换为Comparable[Int]       * String可以被转换为RichString. 而RichString是Ordered[String] 的子类.       */     val pair_int = new Pair_Int(3 ,45)     println(pair_int.bigger)     val pair_better = new Pair_Better(39 ,5)     println(pair_better.smaller) } }

8.6 上下文界定(context bounds)

上下文界定的形式为 T : M, 其中M 必须为泛型类, 必须存在一个M[T]的隐式值.

class Pair_Context[T : Ordering](val first: T, val second: T){ def smaller(implicit ord: Ordering[T]) = if(ord.compare(first, second) < 0) first else second } object Context_Bound { def main(args: Array[String]) { val pair = new Pair_Context("Spark", "Hadoop") println(pair.smaller) val int = new Pair_Context(3, 5) println(int.smaller)   } }

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 深圳大数据培训学习:继承--【千锋】

    也可以把单个方法或者字段声明为final,以确保它不能被重写,注意和Java的不同,Java中final修饰的字段意味着不可变。

    深圳java培训技术
  • 深圳Web前端学习:js中的模块化--【千锋】

    我们知道最常见的模块化方案有CommonJS、AMD、CMD、ES6,AMD规范一般用于浏览器,异步的,因为模块加载是异步的,js解释是同步的,所以有时候导致依...

    深圳java培训技术
  • 深圳大数据培训学习:方法的嵌套--【千锋】

    object EmbedDemo { def add3(x:Int,y:Int,z:Int)={ def add2(x:Int,y:Int)={    ...

    深圳java培训技术
  • 就算不做数据分析师也要学会这8个IF函数

    今天所讲的IF函数,包括excel中含有IF的系列函数,共有8个,每个函数列举最了常用的2~3个公式,希望能对同学们有用。 一、IF函数 作用:根据条件进行判断...

    CDA数据分析师
  • 业界 | 关于李飞飞、李佳重磅加盟 Google,这里有三个有意思的地方

    今日,谷歌对外宣布斯坦福大学人工智能实验室主任李飞飞,和前 Snapchat 研究主管李佳(音译),这两位华裔女科学家将担任谷歌云机器学习部门的负责人。 女性在...

    AI科技评论
  • 一文详解scala泛型及类型限定

    今天知识星球球友,微信问浪尖了一个spark源码阅读中的类型限定问题。这个在spark源码很多处出现,所以今天浪尖就整理一下scala类型限定的内容。希望对大家...

    Spark学习技巧
  • 加密劫持的潜在风险

    对于任何企业而言,隐私和安全性始终是关注的焦点。攻击者试图渗透到公司系统并窃取重要业务和客户信息,攻击的种类层出不穷,攻击速度也越来越快。网络攻击似乎永不停歇。...

    FB客服
  • 在Centos7.3搭建Yum私有仓库

    使用本地iso镜像创建本地yum仓库,该方法不推荐,只针对yum服务器无法上公网的环境下操作,毕竟iso镜像里的包非常有限。

    菲宇
  • SDP(7):Cassandra- Cassandra-Engine:Streaming

      akka在alpakka工具包里提供了对cassandra数据库的streaming功能。简单来讲就是用一个CQL-statement读取cassandra...

    用户1150956
  • 医疗保健:2019年需要关注的5种AI趋势

    人工智能已经风靡行业。从执行简单任务到解决复杂问题,其功能无疑使其成为每项任务背后的主要推动力,无论是任何行业,还是“ 医疗保健”。 “人工智能毫无疑问地通过显...

    Java架构师历程

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动