900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 大数据常用语言Scala(三十六):scala高级用法 泛型

大数据常用语言Scala(三十六):scala高级用法 泛型

时间:2019-08-18 06:27:27

相关推荐

大数据常用语言Scala(三十六):scala高级用法 泛型

目录

泛型

定义一个泛型方法

定义一个泛型类

上下界

协变、逆变、非变

非变

协变

逆变

泛型

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

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

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

定义一个泛型方法

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

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

加入泛型支持

不考虑泛型的实现

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

加入泛型支持

defgetMiddle[A](arr:Array[A])=arr(arr.length /2)defmain(args:Array[String]):Unit={valarr1 =Array(1,2,3,4,5)valarr2 =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

// 这个名字可以任意取

classPair[T,S](valfirst:T,valsecond:S)caseclassPerson(varname:String,valage:Int)objectPair{defmain(args:Array[String]):Unit={valp1 =newPair[String,Int]("张三",10)valp2 =newPair[String,String]("张三","1988-02-19")valp3 =newPair[Person,Person](Person("张三",20),Person("李四",30))}}

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

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

上下界

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

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

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

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

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

// 类名后面的方括号,就表示这个类可以使用两个类型、分别是T和S// 这个名字可以任意取classPair[T <:Person,S <:Person](valfirst:T,valsecond:S){defchat(msg:String)=println(s"${first.name}对${second.name}说: $msg")}classPerson(varname:String,valage:Int)objectPair{defmain(args:Array[String]):Unit={valp3 =newPair(newPerson("张三",20),newPerson("李四",30))p3.chat("你好啊!")}}

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

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

// 类名后面的方括号,就表示这个类可以使用两个类型、分别是T和S// 这个名字可以任意取classPair[T <:Person,S >:Policeman <:Person](valfirst:T,valsecond:S){defchat(msg:String)=println(s"${first.name}对${second.name}说: $msg")}classPerson(varname:String,valage:Int)classPoliceman(name:String,age:Int)extendsPerson(name,age)classSuperman(name:String)extendsPoliceman(name,-1)objectPair{defmain(args:Array[String]):Unit={// 编译错误:第二个参数必须是Person的子类(包括本身)、Policeman的父类(包括本身)valp3 =newPair(newPerson("张三",20),newSuperman("李四"))p3.chat("你好啊!")}}

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

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

协变、逆变、非变

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

如果是泛型之间呢?

来一个类型转换的问题:

classPair[T]objectPair{defmain(args:Array[String]):Unit={valp1 =Pair("hello")// 编译报错,无法将p1转换为p2valp2: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]的子类型。这种情况,参数化类型的方向和类型的方向是相反的。

示例:

classSuperclassSub extendsSuper//非变classTemp1[A](title:String)//协变classTemp2[+A](title:String)//逆变classTemp3[-A](title:String)objectCovariance_demo {defmain(args:Array[String]):Unit={vala =newSub()// 没有问题,Sub是Super的子类valb:Super =a// 非变valt1:Temp1[Sub]=newTemp1[Sub]("测试")// 报错!默认不允许转换// val t2:Temp1[Super] = t1// 协变valt3:Temp2[Sub]=newTemp2[Sub]("测试")valt4:Temp2[Super]=t3// 非变valt5:Temp3[Super]=newTemp3[Super]("测试")valt6:Temp3[Sub]=t5}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。